From f6f5b5b900ad7b39e864c95a7fff435c0a261617 Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Tue, 7 Apr 2026 20:31:15 -0400 Subject: [PATCH] Fix GH-17144: type inference narrowing on ZEND_FETCH_DIM_W FETCH_DIM_W stripped MAY_BE_ARRAY_EMPTY when key_type had any valid key bit set. As the key operand's type widened across iterations (e.g. from MAY_BE_ARRAY to MAY_BE_ARRAY|MAY_BE_LONG), key_type transitioned from 0 to non-zero, flipping the strip from inactive to active. The resulting type lost MAY_BE_ARRAY_EMPTY mid-iteration, tripping the narrowing assertion. Stripping unconditionally is unsound: $a = []; $a[$a] = 1; throws before the write, leaving the array empty. Strip only when the key operand is guaranteed a valid array key, i.e. when op2 is IS_UNUSED (append) or t2 contains no MAY_BE_ARRAY or MAY_BE_OBJECT bits. As t2 widens, this condition can only flip from true to false, so the result type monotonically gains MAY_BE_ARRAY_EMPTY back rather than losing it. Test covers both the original narrowing reproducer and the invalid-key throw path. Closes GH-17144 --- Zend/Optimizer/zend_inference.c | 4 +++- Zend/tests/gh17144.phpt | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh17144.phpt diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index f0d8d873977e..765fe253cbac 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -3716,7 +3716,9 @@ static zend_always_inline zend_result _zend_update_type_info( break; } } - if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG) { + if (opline->opcode != ZEND_FETCH_DIM_FUNC_ARG + && (opline->op2_type == IS_UNUSED + || !(t2 & (MAY_BE_ARRAY|MAY_BE_OBJECT)))) { tmp &= ~MAY_BE_ARRAY_EMPTY; } } diff --git a/Zend/tests/gh17144.phpt b/Zend/tests/gh17144.phpt new file mode 100644 index 000000000000..b9a39e9f8314 --- /dev/null +++ b/Zend/tests/gh17144.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-17144 (Assertion failure during type inference of ZEND_FETCH_DIM_W) +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.jit=1254 +--EXTENSIONS-- +opcache +--FILE-- + 1, + ]; + } +} + +function arrayKeyThrows() { + $a = []; + try { + $a[$a] = 1; + } catch (\Throwable $e) {} + return $a; +} + +var_dump(arrayKeyThrows()); +echo "Done\n"; +?> +--EXPECT-- +array(0) { +} +Done