From 0905a31392e0822b14fdbd4951bdc62e3c679d38 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 9 Jan 2026 11:33:02 +0100 Subject: [PATCH 1/3] Core: fix missing deprecation when accessing null array key with JIT --- Zend/Optimizer/sccp.c | 12 ++++++++++++ ext/opcache/tests/jit/fetch_dim_r_001.phpt | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index 7e2fc2db1b256..643e79d68ba35 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -1535,6 +1535,12 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); + if (op2 && Z_TYPE_P(op2) == IS_NULL) { + /* Emits deprecation at run-time. */ + SET_RESULT_BOT(result); + break; + } + if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST_R)) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1546,6 +1552,12 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); + if (op2 && Z_TYPE_P(op2) == IS_NULL) { + /* Emits deprecation at run-time. */ + SET_RESULT_BOT(result); + break; + } + if (ct_eval_isset_dim(&zv, opline->extended_value, op1, op2) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); diff --git a/ext/opcache/tests/jit/fetch_dim_r_001.phpt b/ext/opcache/tests/jit/fetch_dim_r_001.phpt index 3ff56263db683..819ec7edca655 100644 --- a/ext/opcache/tests/jit/fetch_dim_r_001.phpt +++ b/ext/opcache/tests/jit/fetch_dim_r_001.phpt @@ -30,7 +30,7 @@ function foo() { } foo(); ?> ---EXPECT-- +--EXPECTF-- int(1) int(3) int(2) @@ -38,6 +38,8 @@ int(1) int(3) int(1) int(2) + +Deprecated: Using null as an array offset is deprecated, use an empty string instead in %s on line %d int(4) int(5) int(5) From 3e8a7ef2b1917e8241db4b6274b9dbabb285852d Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 12 Jan 2026 10:22:52 +0100 Subject: [PATCH 2/3] address Ilija and Dmitry comments --- Zend/Optimizer/sccp.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index 643e79d68ba35..8287df040c890 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -363,8 +363,7 @@ static inline zend_result zval_to_string_offset(zend_long *result, zval *op) { static inline zend_result fetch_array_elem(zval **result, zval *op1, zval *op2) { switch (Z_TYPE_P(op2)) { case IS_NULL: - *result = zend_hash_find(Z_ARR_P(op1), ZSTR_EMPTY_ALLOC()); - return SUCCESS; + return FAILURE; case IS_FALSE: *result = zend_hash_index_find(Z_ARR_P(op1), 0); return SUCCESS; @@ -428,6 +427,9 @@ static inline zend_result ct_eval_isset_isempty(zval *result, uint32_t extended_ } static inline zend_result ct_eval_isset_dim(zval *result, uint32_t extended_value, zval *op1, zval *op2) { + if (Z_TYPE_P(op2) == IS_NULL) { + return FAILURE; + } if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) { zval *value; if (fetch_array_elem(&value, op1, op2) == FAILURE) { @@ -1535,12 +1537,6 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); - if (op2 && Z_TYPE_P(op2) == IS_NULL) { - /* Emits deprecation at run-time. */ - SET_RESULT_BOT(result); - break; - } - if (ct_eval_fetch_dim(&zv, op1, op2, (opline->opcode != ZEND_FETCH_LIST_R)) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); @@ -1552,12 +1548,6 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o SKIP_IF_TOP(op1); SKIP_IF_TOP(op2); - if (op2 && Z_TYPE_P(op2) == IS_NULL) { - /* Emits deprecation at run-time. */ - SET_RESULT_BOT(result); - break; - } - if (ct_eval_isset_dim(&zv, opline->extended_value, op1, op2) == SUCCESS) { SET_RESULT(result, &zv); zval_ptr_dtor_nogc(&zv); From ac8c90124ee78589fddb2a4bec47ecc1d692dafe Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Fri, 30 Jan 2026 09:42:09 +0100 Subject: [PATCH 3/3] address Ilija comments --- NEWS | 2 ++ Zend/Optimizer/sccp.c | 3 --- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 07c66ec833e0f..c6bedf8ed114f 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,8 @@ PHP NEWS . Fixed bug GH-21059 (Segfault when preloading constant AST closure). (ilutov) . Fixed bug GH-21072 (Crash on (unset) cast in constant expression). (arshidkv12) + . Fix deprecation now showing when accessing null key of an array with JIT. + (alexandre-daubois) - Windows: . Fixed compilation with clang (missing intrin.h include). (Kévin Dunglas) diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index 8287df040c890..87d7507d4f9a4 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -427,9 +427,6 @@ static inline zend_result ct_eval_isset_isempty(zval *result, uint32_t extended_ } static inline zend_result ct_eval_isset_dim(zval *result, uint32_t extended_value, zval *op1, zval *op2) { - if (Z_TYPE_P(op2) == IS_NULL) { - return FAILURE; - } if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) { zval *value; if (fetch_array_elem(&value, op1, op2) == FAILURE) {