Skip to content

Commit 8c312ba

Browse files
committed
Fix use-after-free in property coercion with __toString()
This was only partially fixed in PHP-8.3. Backports and fixes the case for both initialized and uninitialized property writes. Fixes GH-14969 Closes GH-14971
1 parent 6d0db52 commit 8c312ba

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ PHP NEWS
1010
(nielsdos)
1111
. Fixed OSS-Fuzz #69765. (nielsdos)
1212
. Fixed bug GH-14741 (Segmentation fault in Zend/zend_types.h). (nielsdos)
13+
. Fixed bug GH-14969 (Use-after-free in property coercion with __toString()).
14+
(ilutov)
1315

1416
- Dom:
1517
. Fixed bug GH-14702 (DOMDocument::xinclude() crash). (nielsdos)

Zend/tests/gh14969.phpt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
GH-14969: Crash on coercion with throwing __toString()
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public function __toString() {
8+
global $c;
9+
$c = [];
10+
throw new Exception(__METHOD__);
11+
}
12+
}
13+
14+
class D {
15+
public string $prop;
16+
}
17+
18+
$c = new C();
19+
$d = new D();
20+
try {
21+
$d->prop = $c;
22+
} catch (Throwable $e) {
23+
echo $e->getMessage(), "\n";
24+
}
25+
var_dump($d);
26+
27+
$c = new C();
28+
$d->prop = 'foo';
29+
try {
30+
$d->prop = $c;
31+
} catch (Throwable $e) {
32+
echo $e->getMessage(), "\n";
33+
}
34+
var_dump($d);
35+
36+
?>
37+
--EXPECTF--
38+
C::__toString
39+
object(D)#%d (0) {
40+
["prop"]=>
41+
uninitialized(string)
42+
}
43+
C::__toString
44+
object(D)#2 (1) {
45+
["prop"]=>
46+
string(3) "foo"
47+
}

Zend/zend_object_handlers.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
819819

820820
ZVAL_COPY_VALUE(&tmp, value);
821821
if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) {
822-
Z_TRY_DELREF_P(value);
822+
zval_ptr_dtor(&tmp);
823823
variable_ptr = &EG(error_zval);
824824
goto exit;
825825
}
@@ -890,7 +890,7 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva
890890

891891
ZVAL_COPY_VALUE(&tmp, value);
892892
if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, property_uses_strict_types()))) {
893-
zval_ptr_dtor(value);
893+
zval_ptr_dtor(&tmp);
894894
goto exit;
895895
}
896896
value = &tmp;

0 commit comments

Comments
 (0)