We partially fixed this in bug #78379, but still don't handle
the case where the properties array is marked as grey first,
which causes a delref to not be performed later.
Fix this by treating the object properties HT the same way as
other refcounted values, including addrefs/delrefs. The object
dtor code already handles properties HT with NULL GC type, so
out of order destruction should not be a problem.
Fixes oss-fuzz #36023.
TMPVAR operands are destroyed using zval_ptr_dtor_nogc(), because
they usually cannot contain cycles. However, there are some rare
exceptions where this is possible, e.g. unserialize() return value.
In such cases we rely on the producing code to root the value. If
a GC run occurs between the rooting and consumption of the value,
we would end up leaking it. To avoid this, root all live TMPVAR
values after a GC run.
Closes GH-7210.
Since PHP 7.4 objects that have a destructor require two GC runs
to be collected. Currently the collection is delayed to the next
automatic GC run. However, in some cases this may result in a large
increase in memory usage, as in one of the cases of bug #79519.
See also bug #78933 and bug #81117 where the current behavior is
unexpected for users.
This patch will automatically rerun GC if destructors were encountered.
I think this should not have much cost, because it is very likely that
objects on which the destructor has been called really are garbage,
so the extra GC run should not be doing wasted work.
Closes GH-5581.
On further consideration, we should be making use of the fact
that zend_object_iterator is also a zend_object here, and let
GC handle the get_gc call on it. Calling get_gc recursively like
this is generally not safe, because there is only one gc_buffer.
This also happens to be much simpler...
Moving the zend_iterator_dtor from dual_it_dtor to dual_it_free_storage
exposed this GC leak in an existing test. Forward the result of the
iterator get_gc to the dual_it get_gc.
We're starting to see a mix between uses of zend_bool and bool.
Replace all usages with the standard bool type everywhere.
Of course, zend_bool is retained as an alias.
While the initial threshold is set to 10001 roots, the threshold
adjustment logic may then set it to 10000. The exact value really
doesn't matter, but we should make it consistent.
We should be doing this anyway to prevent stack overflow, but on
master this is important for an additional reason: The temporary
GC buffer provided for get_gc handlers may get reused if the scan
is performed recursively instead of indirected via the GC stack.
This fixes oss-fuzz #23350.
get_gc() implementations that need to explore heterogeneous data
currently work by computing how many GC entries they need,
allocating a buffer for that and storing it on the object. This
is inefficient and wastes memory, because the buffer is retained
after the GC run.
This commit adds an API for a single global GC buffer, which can
be reused by get_gc implementations (as only one get_gc call is
ever active at the same time). The GC buffer will automatically
grow during the GC run and be discarded at the end.
We no longer protect GC during the destroy phase, so we need to
deal with buffer reallocation.
Note that the implementation of spl_SplObjectStorage_free_storage
will call the destructor of SplObjectStorage, and free the instance properties,
which I think is what caused the root buffer to be reallocated.
(`current` is a pointer for an index within the root buffer?)
This fixes bug #78811 for me.
Closes GH-4935
The properties HT may be a GC root itself, so we need to remove it.
I'm not sure this issue actually applies to PHP 7.2, but committing
it there to be safe. As seen from the test case, the handling here
is rather buggy on 7.2.
For objects with destructors, we will now only call the destructor
in the initial GC run, and remove any nested data. The object is
marked purple so it will be considered a root for the next GC run,
at which point it will be fully destroyed, if possible.
GC counts change on a number of tests, as the objects now get
destroyed later.