Summary
At script scope (not inside a function), ++/-- produces wrong values once a program does
more than a couple of operations. Individually each shape is fine; combined they are not.
VM is unaffected (57/57). AOT only.
Reproducers
1 — a for loop after other script-scope inc/dec statements
<?php
$n = 5; $n--; echo $n, "\n";
$n--; $n--; echo $n, "\n";
--$n; echo $n, "\n";
$n++; echo $n, "\n";
$acc = 0;
for ($i = 0; $i < 5; ++$i) { ++$acc; }
echo $acc, "\n";
zend: 4 2 1 2 5
aot : 4 2 1 2 0 <- accumulator is 0
The identical loop on its own is correct:
<?php $acc = 0; for ($i = 0; $i < 5; ++$i) { ++$acc; } echo $acc, "\n"; // aot: 5, correct
2 — a second script-scope variable (intermittent heap corruption)
<?php $a = 5; $a--; $b = 9; $b--; echo "$a $b\n";
zend: 4 8
aot : free(): invalid pointer (core dump)
Note this one is not deterministic in shape — the three-variable version
($a,$b,$c + interpolation) prints 4 8 1 correctly. Consistent with heap corruption whose
manifestation depends on allocation layout rather than a clean "second variable" rule. I could not
reduce it further.
Not caused by #23781, and not by the resource guard
Verified by probe rather than assumed, on the same tree:
|
first $n-- |
later ops |
| resource guard emitted (normal) |
4 correct |
wrong |
| resource guard force-disabled |
5 wrong |
wrong |
Force-disabling the guard makes it worse — even the first statement breaks. So the guard is not
the cause, and neither is #23781's elision of it (#23840 was a separate, now-fixed regression that
made all script-scope inc/dec no-ops).
Whatever this is, it predates both and lives in the script-scope store path.
Coverage
test/differential/cases/g08_toplevel_incdec.php gates the plain-statement shapes on both
backends. It deliberately stops short of these two, with the exclusion documented in the file
pointing here — including them would leave it permanently red and useless as a gate.
Environment: php-compiler:22.04-dev, PHP 8.2.32, LLVM 9, php bin/compile.php -o <bin> <file>.
Summary
At script scope (not inside a function),
++/--produces wrong values once a program doesmore than a couple of operations. Individually each shape is fine; combined they are not.
VM is unaffected (57/57). AOT only.
Reproducers
1 — a
forloop after other script-scope inc/dec statementsThe identical loop on its own is correct:
2 — a second script-scope variable (intermittent heap corruption)
Note this one is not deterministic in shape — the three-variable version
(
$a,$b,$c+ interpolation) prints4 8 1correctly. Consistent with heap corruption whosemanifestation depends on allocation layout rather than a clean "second variable" rule. I could not
reduce it further.
Not caused by #23781, and not by the resource guard
Verified by probe rather than assumed, on the same tree:
$n--4correct5wrongForce-disabling the guard makes it worse — even the first statement breaks. So the guard is not
the cause, and neither is #23781's elision of it (#23840 was a separate, now-fixed regression that
made all script-scope inc/dec no-ops).
Whatever this is, it predates both and lives in the script-scope store path.
Coverage
test/differential/cases/g08_toplevel_incdec.phpgates the plain-statement shapes on bothbackends. It deliberately stops short of these two, with the exclusion documented in the file
pointing here — including them would leave it permanently red and useless as a gate.
Environment:
php-compiler:22.04-dev, PHP 8.2.32, LLVM 9,php bin/compile.php -o <bin> <file>.