@@ -5,6 +5,42 @@ All notable changes to this extension will be documented in this file.
55The format is based on [ Keep a Changelog] ( https://keepachangelog.com/en/1.1.0/ ) ,
66and this project adheres to [ Semantic Versioning] ( https://semver.org/spec/v2.0.0.html ) .
77
8+ ## [ 0.5.1] - 2026-04-17
9+
10+ ### Fixed
11+
12+ - ` deepclone_to_array() ` heap-use-after-free when a referenced value
13+ is copied into an array that later transitions from packed to hash
14+ storage. ` dc_copy_array ` stashed pointers into the dst hash in
15+ ` ref_entry->tree_pos ` for later dtor; the first insert with a string
16+ key triggered ` zend_hash_packed_to_hash() ` which freed the packed
17+ storage, leaving earlier tree_pos pointers dangling. Fix: force
18+ mixed/hash storage on dst before the loop.
19+ - ` deepclone_to_array() ` unsound refcount-based pool-skip: skipping the
20+ object-pool lookup when ` Z_REFCOUNT_P(src) == 1 ` (without
21+ ` __serialize ` ) was incorrect when the object is reached via a SHARED
22+ parent array — the parent is walked multiple times and the object is
23+ visited twice, but the skip bypassed the pool and tripped
24+ ` zend_hash_index_add_new ` 's assertion on the second visit. Fix:
25+ always do the pool lookup.
26+ - ` deepclone_to_array() ` ` scope_name ` leak on private-property skip:
27+ the ` goto next_prop ` paths (for ` __sleep ` -filtered or proto-identical
28+ values) bypassed the release of ` scope_name ` allocated in the
29+ private-key branch. Fix: track ` scope_name_owned ` and release at
30+ ` next_prop ` .
31+ - ` deepclone_from_array() ` DoS via unbounded IS_LONG ` objectMeta `
32+ count: a 59-byte payload with ` objectMeta ` as a large integer (e.g.
33+ ` 844067442 ` ) triggered multi-GB allocations. Fix: cap the IS_LONG
34+ form at 1 << 20 (1M); payloads needing more should use the array form
35+ which is naturally bounded by hash-table size.
36+
37+ All four were found by libFuzzer harnesses with ASAN/UBSAN — two
38+ targeting ` deepclone_from_array() ` and ` deepclone_hydrate() ` directly,
39+ and one round-trip harness that builds a graph from a tiny stack
40+ machine and feeds it through ` deepclone_to_array() ` /
41+ ` deepclone_from_array() ` . Total: 8.47M executions on hydrate and
42+ 6.98M on from_array clean after fixes, plus ~ million roundtrip execs.
43+
844## [ 0.5.0] - 2026-04-16
945
1046### BC Break
0 commit comments