Skip to content

AOT: string conversion of an int renders "Resource id #N" when the value collides with a live handle #23811

Description

@PurHur

Summary

In an AOT binary, converting an integer to a string consults the resource registry. If the
integer's value happens to equal a live resource handle id, it renders as Resource id #N instead
of the number.

This is the same root design flaw as #23483 — resource handles are stored as native longs and
php-types has no resource type, so Type::TYPE_LONG covers both — but in the string-conversion
path rather than inc/dec.

Reproducer

<?php
$fh  = fopen('php://memory', 'r+');
$fh2 = fopen('php://memory', 'r+');
$a = 1; ++$a;      // $a === 2, and handle #2 is live
$b = 2; ++$b;
$c = 3; ++$c;
$d = 4; --$d;
echo "$a $b $c $d\n";
zend: 2 3 4 3
aot : Resource id #2 3 4 3

Only $a is affected, because only its value (2) collides with a live handle id. The other three
render correctly. Opening a different number of resources moves which integer is corrupted, which
is the tell.

Note the value is arithmetically correct — 2 — it is only the rendering that treats it as a
resource. Any int-to-string conversion is presumably affected: interpolation, echo of a
concatenation, (string) casts, strval(), array keys printed by print_r.

Second defect in the same program

The same file also mis-evaluates a plain decrement, and then truncates:

$n = 0; $n--; $n--;
echo $n, "\n";      // zend: -2   aot: 0

After printing 0 the program produces no further output — the trailing fread/echo "done"
lines never run. Filed together because they share a reproducer; they may well be separate causes.

Context

Found by test/differential/cases/g07_incdec_resource_provenance.php, which was written for #23483
specifically to test integers colliding with plausible handle ids while resources are open. It
passes under VM and fails under AOT.

Not a regression from #23483's fix — measured. With lib/ at 544d1dca9 (immediately before that
change) the same program dies with rc=134/SIGABRT and no output at all; with the fix it gets
far enough to produce the wrong output above. So this is pre-existing breakage that the fix
un-masked.

Environment: php-compiler:22.04-dev, PHP 8.2.32, LLVM 9, php bin/compile.php -o <bin> <file>.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions