Skip to content

Regression: substr() negative offset + nested string builtin arg #1 — returns offset not slice (re-#10673, ext/standard/string.c) #13616

Closed

Description

@PurHur

Category

stdlib · php-src-strict · regression

Problem

Closed #10673 regressed: when substr() argument #1 is a nested string-return builtin and argument #2 is a negative offset, VM returns the decimal offset string (-4, -2, …) instead of the correct tail slice.

Zend pattern used for file modes: substr(sprintf('%o', fileperms($path)), -4).

Positive offsets with the same nesting work (substr(sprintf('%s','abc'), 0, 2) → ab).

php-src reference

Repro (verified 2026-06-29)

php test/repro/maintainer_gap_substr_sprintf_nested.php
php bin/vm.php test/repro/maintainer_gap_substr_sprintf_nested.php
Call Zend VM
substr(sprintf('%o', 33188), -4) 0644 -4 ❌
substr(dechex(255), -2) ff -2 ❌
substr(str_pad('1',5,'0'), -3) 000 -3 ❌
substr(sprintf('%o', fileperms($f)), -4) after chmod($f,0644) 0644 -4 ❌
substr(sprintf('%s','abcdef'), 0, 2) (control) ab ab ✓

Scope (PHP-in-PHP first)

Layer Path
VM call bridge nested return-value materialization for string builtins used as substr subject
Stdlib ext/standard/ — no new runtime/*.c branches
Related #9547 family (nested array builtins); this repro is string-return + negative offset

Done when (php-src-strict)

  • All rows in repro table match Zend
  • test/repro/maintainer_gap_substr_sprintf_nested.php exits 0 on VM
  • Targeted compliance guard under test/compliance/cases/stdlib/

Verification

php bin/vm.php test/repro/maintainer_gap_substr_sprintf_nested.php

Links

Activity

  1. added
    enhancementNew feature or request
    phase-4:stdlibPhase 4 – stdlib for web apps
    area:vmVirtual machine
    implementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claim
    on Jun 29, 2026
  2. PurHur commented on Jun 29, 2026

    @PurHur
    OwnerAuthor

    claim: cursor-agent-lane-c — batch (issues #13616); VM nested string builtin + substr negative offset regression (lib/ call bridge, not ext/ implementation)

  3. PurHur commented on Jun 29, 2026

    @PurHur
    OwnerAuthor

    Merged via #13632

    Fix: sibling inline call-arg producer wiring in lib/Compiler.php — UnaryMinus preludes between hoisted FuncCall producers no longer break siblingMultiArgProducerWiresByDistinctDeadArgOrdinal; nested-only producers (e.g. fileperms feeding sprintf) are skipped when resolving firstSibling for substr(..., -N) chains.

    Verification:

    ./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
    php bin/vm.php test/repro/maintainer_gap_substr_sprintf_nested.php
    php vendor/bin/phpunit test/compliance/VMTest.php --filter nested_substr_sprintf
    '

    repro exit=0; compliance green.

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

    area:vmVirtual machineenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-4:stdlibPhase 4 – stdlib for web appsstdlib

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions