Unconditionally execute assignment of EXIT_CODE. Otherwise, the variable bleeds
into the next iteration. Also add newline before ::endgroup::. ASAN does not add
a trailing newline.
Since GH-13188 we're no longer immediately updating iterator positions when
deleting array elements. zend_hash_rehash() needs to adapt accordingly by
adjusting nInternalPosition for IS_UNDEF elements. This is already the case for
array iterators.
Fixes GH-19280
Closes GH-19323
There are 2 issues:
1. When a MULTISORT_ABORT happens, it frees func, but func may point to
ARRAYG(multisort_func), which would be a problem with nested
invocations as it can destroy that of the "parent" invocation.
To solve this, delay assigning to the globals.
2. The old globals were not restored which means that nested invocations
with different flags will cause a wrong sorting function to be used.
Closes GH-19319.
Generator::throw() on a running generator is not allowed. It throws "Cannot
resume an already running generator" when trying to resume the generator to
handle the provided exception.
However, when calling Generator::throw() on a generator with a non-Generator
delegate, we release the delegate regardless. If a Fiber was suspended in
the delegate, this causes use after frees when the Fiber is resumed.
Fix this by throwing "Cannot resume an already running generator" earlier.
Fixes GH-19326
Closes GH-19327
Normally we prevent generators from being resumed while they are already
running, but we failed to do so for generators delegating to non-Generators. As
a result such generator can be resumed, terminated, which causes unexpected
results (crashes) later.
In gh19306.phpt in particular, the generator delegate It::getIterator() suspends
while being called by generator g(). We then resume g(), which throws while
trying to resume It::getIterator(). This causes g() and It::getIterator()
to be released. We then UAF when resuming the Fiber in It::getIterator().
Fix this by ensuring that generators are marked as running while they fetch
the next value from the delegate.
Fixes GH-19306
Closes GH-19315
Having an empty result array is not a problem, because zend_hash_extend()
will initialize it. Except it does not when the number of elements to add
equals 0, which leaves the array uninitialized and therefore does not
set the packed flag, causing the assertion failure.
Technically, removing the assert would also work and save a check.
On the other hand, this check could also prevent some real work to be
done and should be relatively cheap as we already have to compute the
sum anyway.
Closes GH-19318.