Skip to content

Stdlib: array_push()/array_unshift()/array_multisort() — argument unpacking (...$values) VM Refcount fatal (ext/standard/array.c, php-src-strict) #6689

Closed

Description

@PurHur

Category

stdlib | language (call lowering)

Problem

Zend accepts argument unpacking (...$values) on builtins whose first parameter is a by-reference array (array_push, array_unshift, array_multisort). Our VM aborts with an internal Refcount is > 1, but was asserted to be 1 instead of mutating the array or completing the sort.

This is a variadic unpack + by-ref slot bug in shared call lowering, not a missing builtin implementation.

php-src reference

Repro

./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
php test/repro/array_push_unshift_unpack_refcnt.php          # Zend: unshift=[3,4,1,2] push=[1,2,3,4]
php bin/vm.php test/repro/array_push_unshift_unpack_refcnt.php # VM: Refcount is > 1, but was asserted to be 1
php test/repro/array_multisort_unpack_refcnt.php               # Zend: ok
php bin/vm.php test/repro/array_multisort_unpack_refcnt.php    # VM: same Refcount fatal
'

Minimal inline:

<?php
$a = [1, 2];
array_unshift($a, ...[3, 4]); // VM fatal

$b = [1, 2];
array_push($b, ...[3, 4]);    // VM fatal

array_multisort(...[[3, 1, 2], ['c', 'a', 'b']]); // VM fatal

Scope (PHP-in-PHP first)

Path Work
lib/VM.php Fix variadic unpack into by-ref argument slots
ext/standard/ array_push.php, array_unshift.php, array_multisort.php — handlers OK once frames pass expanded args
Related refcount aborts #6521 (parse_str), #5840 (shuffle), #4738 (stream_context_create)
C runtime No new runtime/*.c branches

Expected (php-src-strict)

Match Zend: arrays mutate / sort completes; no VM abort. JIT/AOT mirror VM once call lowering is fixed.

Verification

  • Add test/compliance/cases/stdlib/array_push_unpack.phpt (and unshift/multisort siblings)
  • Filter: vendor/bin/phpunit test/compliance/VMTest.php --filter array_push_unpack

Done when

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 6, 2026
  2. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    claim: worker-lane-c — starting this run

  3. PurHur commented on Jun 8, 2026

    @PurHur
    OwnerAuthor

    Merged via #7602

    Fix: COW-separate by-ref array zvals for internal builtins in lib/VM.php::resolveOutgoingCallArgs() (separateInternalByRefArgsForWrite) before handlers mutate shared HashTables after call-time unpack expansion.

    Verification:
    ```bash
    ./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
    php bin/vm.php test/repro/array_push_unshift_unpack_refcnt.php
    php bin/vm.php test/repro/array_multisort_unpack_refcnt.php
    vendor/bin/phpunit test/compliance/VMTest.php --filter "array_push_unpack|array_unshift_unpack|array_multisort_unpack|array_push_empty_spread|stdlib/array_push""
    '
    ```
    → push/unshift unpack repro green; compliance OK (5 tests).

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 apps

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions