diff options
author | Luca Di Sera <[email protected]> | 2025-07-01 14:39:35 +0200 |
---|---|---|
committer | Luca Di Sera <[email protected]> | 2025-07-03 19:24:23 +0200 |
commit | 64b3748b39db6241a914da8c358d245061977409 (patch) | |
tree | 591b7b3f423e2516bfaa076f51dc0227241f538b /src/quickcontrols/basic/ScrollBar.qml | |
parent | 23df452196c165ee8fbc7a4efc82a357bca5ca16 (diff) |
When allocating an object on the JS heap the garbage collector might be
run as part of the allocation, in particular as a way to possibly make
space when the memory space is starting to get filled up.
When the garbage collector runs, it is possible, as part of its normal
processing, that it will access the JS stack, and try to interact with
the objects that are stored on it.
In particular, while collecting from the JS stack, the garbage collector
will need to mark all Managed objects that are found on it.
When allocating on the JS stack it is possible that the allocation and
the initialization of the allocated memory are performed in separate
steps.
When this is so, it is possible for the allocated element on the stack
to represent garbage memory in between being allocated and being
initialized.
Since the garbage collector can inspect all elements on the stack as
part of its processing, it is possible for it to inspect an element that
represents garbage memory if it runs in between the allocation and
initialization of that stack element.
Furthermore, since each allocation might run the garbage collector, then
any allocation in between the allocation and initialization of such a
stack element can access garbage memory.
In particular, if the garbage memory represents a pointer to a
previously existing Managed object that was swept, the garbage collector
might try to mark an object that shouldn't be marked.
There are a few cases of this currently in the code-base.
While instantiating a QML file, `QQmlObjectCreator` keeps track of
objects that are created in the process, to avoid premature collection.
As part of this, `ObjectInCreationGCAnchoList::trackObject` will be
called, in turn allocating on an element on the js stack and then
initializing it separately by the creation of `QObjectWrapper`.
The creation of a `QObjectWrapper` generally allocates, such that it can
incur into the above problem.
As part of dealing with the JS spread operator, in particular when
processing the spread element, we juggle with multiple allocation of
uninitialized elements on the js stack.
During this processing multiple part of the code can allocate.
For example, the spread element is handled through the use of an
iterator that, during its creation, might allocate as during the
creation process we might convert the spread argument to object so that
the iterator can deal with it, which would be the case for a spread
argument that is a string.
When allocating an element on the js stack that is bound to a certain
scope, we sometime allow a conversion to be performed on the original
element.
This conversion routine might allocate, and it does do so for the
currently existing conversion to a String and to an Object.
The conversion routine is called after an uninitialized element is
pushed on the stack, and can thus incur into the above issue.
To fix the issue, an additional method was added, `construct`, that
ensures that allocation and initialization happen sequentially with no
allocation in-between, using an initialization value that is passed as
an argument.
The new method was applied to the code affected by the bug, in practice,
reordering the operations in the affected cases such that the
bug-producing allocations happens before the allocation on the stack
such as to avoid the bug while keeping the same semantics.
An exception was taken for the handling of the spread argument, which
has a more complex control flow, where the solution that was used is to
initialize the memory to the empty value as part of the allocation.
A series of test cases showing an example of the issues were added to
`tst_qv4mm`.
The tests make use of the fact that we assert when we find a Managed
object on the js stack that is not in use, as that is a logical error
for the garbage collector, to observe the issue and are thus skipped
when assertions are not enabled.
Change-Id: Id478e16ee22e20e77d01fdfae9a0269d6d709892
Reviewed-by: Ulf Hermann <[email protected]>
Diffstat (limited to 'src/quickcontrols/basic/ScrollBar.qml')
0 files changed, 0 insertions, 0 deletions