Skip to content

Commit a109403

Browse files
committed
Fix GH-21824: Avoid unserialize context reuse during cleanup
1 parent f1d6391 commit a109403

3 files changed

Lines changed: 33 additions & 3 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ PHP NEWS
33
?? ??? ????, PHP 8.6.0alpha1
44

55
- Core:
6+
. Fixed bug GH-21824 (Crash in unserialize()). (Pratik Bhujel)
67
. Added first-class callable cache to share instances for the duration of the
78
request. (ilutov)
89
. It is now possible to use reference assign on WeakMap without the key
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-21824 (Crash in unserialize() with destructor reentry)
3+
--ENV--
4+
USE_ZEND_ALLOC=0
5+
--FILE--
6+
<?php
7+
class Trigger {
8+
public function __destruct() {
9+
@unserialize('i:1;');
10+
}
11+
}
12+
13+
$payload = 'a:1019:{';
14+
for ($i = 0; $i < 1017; $i++) {
15+
$payload .= "i:$i;s:1:\"A\";";
16+
}
17+
$payload .= 'i:1017;O:7:"Trigger":0:{}';
18+
$payload .= 'i:1017;i:0;}';
19+
20+
@unserialize($payload);
21+
echo "Done\n";
22+
?>
23+
--EXPECT--
24+
Done

ext/standard/var_unserializer.re

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,17 @@ PHPAPI php_unserialize_data_t php_var_unserialize_init(void) {
8181

8282
PHPAPI void php_var_unserialize_destroy(php_unserialize_data_t d) {
8383
/* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */
84-
if (BG(serialize_lock) || BG(unserialize).level == 1) {
84+
if (BG(serialize_lock)) {
8585
var_destroy(&d);
8686
efree(d);
87-
}
88-
if (!BG(serialize_lock) && !--BG(unserialize).level) {
87+
} else if (BG(unserialize).level == 1) {
88+
/* var_destroy() may re-enter unserialize() while running destructors. */
8989
BG(unserialize).data = NULL;
90+
BG(unserialize).level = 0;
91+
var_destroy(&d);
92+
efree(d);
93+
} else {
94+
--BG(unserialize).level;
9095
}
9196
}
9297

0 commit comments

Comments
 (0)