[php-src] PR #23545: Fix IS_IDENTICAL_EMPTY_ARRAY specialization for an IS_CONST op1
| From: | Mrmaxmeier | Date: | Wed, 02 Sep 2026 15:20:33 +0000 |
| Subject: | [php-src] PR #23545: Fix IS_IDENTICAL_EMPTY_ARRAY specialization for an IS_CONST op1 | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-38267@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/23545
Author: Mrmaxmeier
Hi,
we ran into an assertion failure in the VM with the
fuzzer-function-jit fuzzing target:
```php
<?php
if (A::class->p === []) {
echo "identical\n";
}
if (A::class->p !== []) {
echo "not identical\n";
}
echo "OK\n";
```
On a debug build this aborts in _get_zval_ptr_tmpvarcv().
ZEND_IS_IDENTICAL_EMPTY_ARRAY is new in 8.5, so this does not affect 8.4.
<details>
<summary>Assertion backtrace for reproducer</summary>
```
/out/php-fuzz-function-jit: Running 1 inputs 100 time(s) each.
Running: /testcase
php-fuzz-function-jit: /src/php-src/Zend/zend_execute.c:402: zval *_get_zval_ptr_tmpvarcv(int,
znode_op, int, zend_execute_data *): Assertion `op_type == (1<<3)' failed.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==15==ERROR: AddressSanitizer: ABRT on unknown address 0x00000000000f (pc 0x7fd4f89f000b bp
0x7fd4f8b65588 sp 0x7fff42d4cc30 T0)
SCARINESS: 10 (signal)
#0 0x7fd4f89f000b in raise (/lib/x86_64-linux-gnu/libc.so.6+0x4300b) (BuildId:
5792732f783158c66fb4f3756458ca24e46e827d)
#1 0x7fd4f89cf858 in abort (/lib/x86_64-linux-gnu/libc.so.6+0x22858) (BuildId:
5792732f783158c66fb4f3756458ca24e46e827d)
#2 0x7fd4f89cf728 (/lib/x86_64-linux-gnu/libc.so.6+0x22728) (BuildId:
5792732f783158c66fb4f3756458ca24e46e827d)
#3 0x7fd4f89e0fd5 in __assert_fail (/lib/x86_64-linux-gnu/libc.so.6+0x33fd5) (BuildId:
5792732f783158c66fb4f3756458ca24e46e827d)
#4 0x56412dbacdc3 in _get_zval_ptr_tmpvarcv /src/php-src/Zend/zend_execute.c:402:3
#5 0x56412dbacdc3 in ZEND_IS_IDENTICAL_EMPTY_ARRAY_SPEC_TMPVARCV_CONST_JMPZ_HANDLER
/src/php-src/Zend/zend_vm_execute.h:14529:8
#6 0x56412df140bb in fuzzer_execute_ex /src/php-src/sapi/fuzzer/fuzzer-execute-common.h:65:12
#7 0x56412da3813d in zend_execute /src/php-src/Zend/zend_vm_execute.h:115989:2
#8 0x56412df153bf in fuzzer_do_request_from_buffer /src/php-src/sapi/fuzzer/fuzzer-sapi.c:293:5
#9 0x56412df13954 in LLVMFuzzerTestOneInput /src/php-src/sapi/fuzzer/fuzzer-function-jit.c:32:2
[..]
DEDUP_TOKEN: raise--abort--
SUMMARY: AddressSanitizer: ABRT (/lib/x86_64-linux-gnu/libc.so.6+0x4300b) (BuildId:
5792732f783158c66fb4f3756458ca24e46e827d) in raise
==15==ABORTING
```
</details>
The ZEND_IS_IDENTICAL_EMPTY_ARRAY / ZEND_IS_NOT_IDENTICAL_EMPTY_ARRAY
specializations are declared for the operand pair TMPVARCV, CONST:
```c
ZEND_VM_TYPE_SPEC_HANDLER(ZEND_IS_IDENTICAL, op->op2_type == IS_CONST && (...),
ZEND_IS_IDENTICAL_EMPTY_ARRAY, TMPVARCV, CONST, ...)
```
but the condition that selects them only ever looked at op2. The other specializations
of these opcodes bail out for a CONST/CONST operand pair, this one did
not. So an IS_CONST op1 still selected a handler that reads its op1 through
_get_zval_ptr_tmpvarcv(), which cannot read a literal and asserts.
Getting there needs the optimizer: type inference proves the property fetch on the
A::class string to be null and substitutes the constant into op1, but the comparison
itself is not folded, which leaves a ZEND_IS_IDENTICAL with two IS_CONST
operands for the specializer to look at.
The fix adds the missing op->op1_type != IS_CONST to the selection condition of both
handlers, which is what the sibling specializations already do.
Thanks!
---
_Found by the CISPA Fandango team while triaging findings in oss-fuzz harnesses._