Commit 8b4ef3a09f0 for php.net
commit 8b4ef3a09f078a69a39ccf4429ed36382f559d4f
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date: Thu Jul 17 19:07:15 2025 +0200
Fix FETCH_OBJ_UNSET IS_UNDEF result
UNSET_OBJ et al. do not expect to find IS_UNDEF results for IS_INDIRECT vars. To
solve this, return IS_NULL from FETCH_OBJ_UNSET when properties are
uninitialized. Do the same for FETCH_STATIC_PROP_IS, as we're otherwise copying
IS_UNDEF into the VAR result, which is not a valid value for VAR.
Fixes OSS-Fuzz #429429090
Closes GH-19160
diff --git a/NEWS b/NEWS
index 062265576af..f42cfc4e5ee 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ PHP NEWS
. It is now possible to use reference assign on WeakMap without the key
needing to be present beforehand. (ndossche)
. Added `clamp()`. (kylekatarnls, thinkverse)
+ . Fix OSS-Fuzz #429429090 (Failed assertion on unset() with uninitialized
+ container). (ilutov)
- Date:
. Update timelib to 2022.16. (Derick)
diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c
index 54670c804d0..9b5561e7fbe 100644
--- a/Zend/Optimizer/zend_inference.c
+++ b/Zend/Optimizer/zend_inference.c
@@ -3840,7 +3840,7 @@ static zend_always_inline zend_result _zend_update_type_info(
tmp &= ~MAY_BE_RC1;
}
if (opline->opcode == ZEND_FETCH_STATIC_PROP_IS) {
- tmp |= MAY_BE_UNDEF;
+ tmp |= MAY_BE_NULL;
}
}
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
diff --git a/Zend/tests/oss_fuzz_429429090.phpt b/Zend/tests/oss_fuzz_429429090.phpt
new file mode 100644
index 00000000000..d5279c2806a
--- /dev/null
+++ b/Zend/tests/oss_fuzz_429429090.phpt
@@ -0,0 +1,20 @@
+--TEST--
+OSS-Fuzz #429429090: FETCH_OBJ_UNSET IS_UNDEF result
+--FILE--
+<?php
+
+class C {
+ public D $x;
+ static D $y;
+}
+
+$c = new C();
+isset($c->x[0]->prop);
+unset($c->x[0]->prop);
+isset(C::$y[0]->prop);
+unset(C::$y[0]->prop);
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c
index 570aac4a8db..a4460286bf6 100644
--- a/Zend/zend_execute.c
+++ b/Zend/zend_execute.c
@@ -3626,6 +3626,9 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
} else if (UNEXPECTED(Z_ISERROR_P(ptr))) {
ZVAL_ERROR(result);
goto end;
+ } else if (type == BP_VAR_UNSET && UNEXPECTED(Z_TYPE_P(ptr) == IS_UNDEF)) {
+ ZVAL_NULL(result);
+ goto end;
}
ZVAL_INDIRECT(result, ptr);
@@ -3777,6 +3780,11 @@ static zend_never_inline zval* zend_fetch_static_property_address_ex(zend_proper
return NULL;
}
+ if (UNEXPECTED(Z_TYPE_P(result) == IS_UNDEF)
+ && (fetch_type == BP_VAR_IS || fetch_type == BP_VAR_UNSET)) {
+ return NULL;
+ }
+
*prop_info = property_info;
if (EXPECTED(op1_type == IS_CONST)
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 9afca6015c5..86de5992a8f 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -1866,7 +1866,7 @@ ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type)
&prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type,
type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC);
if (UNEXPECTED(!prop)) {
- ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS));
+ ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS) || (type == BP_VAR_UNSET));
prop = &EG(uninitialized_zval);
} else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK)
&& (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET)
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index e0c380deedd..62d645c1510 100644
Binary files a/Zend/zend_vm_execute.h and b/Zend/zend_vm_execute.h differ