Skip to content

Commit 583e623

Browse files
Release v0.5.1
1 parent 0bc6dc3 commit 583e623

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,42 @@ All notable changes to this extension will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and 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

php_deepclone.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
extern zend_module_entry deepclone_module_entry;
55
#define phpext_deepclone_ptr &deepclone_module_entry
66

7-
#define PHP_DEEPCLONE_VERSION "0.5.0"
7+
#define PHP_DEEPCLONE_VERSION "0.5.1"
88

99
ZEND_BEGIN_MODULE_GLOBALS(deepclone)
1010
HashTable hydrate_cache;

0 commit comments

Comments
 (0)