[php-src] PR #22921: Fix use-after-free when json_encode() re-enters an ArrayObject
| From: | iliaal | Date: | Wed, 29 Jul 2026 12:56:59 +0000 |
| Subject: | [php-src] PR #22921: Fix use-after-free when json_encode() re-enters an ArrayObject | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-37333@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/22921
Author: iliaal
json_encode() borrows an ArrayObject's storage table for the length of the encode and then runs
userland through JsonSerializable::jsonSerialize() and property hooks.
spl_array_get_hash_table_ptr() hands that same table back to the write paths, so an insert from the
callback grows it and frees the buckets the encoder is iterating; valgrind reports invalid reads in
php_json_encode_array() for the array-backed ArrayObject, ArrayIterator and self-backed cases in the
test. The object-backed branch of that function already separates when the table is borrowed, so
this gives the other two branches the same treatment. Encoding cost is unchanged: the separation
only fires while a borrow is outstanding, and the refcount is 1 the rest of the time.
#20725 proposes the same SEPARATE_ARRAY call at the write sites instead. That placement leaves the
by-reference auto-vivify path through spl_array_get_dimension_ptr() unprotected, which valgrind
still reports as an invalid read, and it does not reach the self-backed case.