Skip to content

Growing a Mixed-promoted array in a loop then iterating+consuming it corrupts the heap #452

Description

@mirchaemanuel

Summary

Growing an array that has been promoted to mixed-element storage (array<mixed>) across loop iterations, then iterating it and consuming each value, corrupts the heap: the program prints wrong/empty output or segfaults. No enum, closure, or object is involved — a plain intval() / (int) cast / += on the foreach value is enough.

Verified on

main (macOS ARM64, default EIR backend). No #349/#449 changes involved — reproduces on a clean main build.

Minimal reproduction

<?php
$vals = [];
for ($i = 0; $i < 2; $i++) {
    $vals[] = 1;      // int
    $vals[] = 2.0;    // float → promotes the array to array<mixed>, then keeps growing
}
$sum = 0;
foreach ($vals as $v) {
    $sum += intval($v);
}
echo $sum, "\n";

Actual

Prints an empty line (and sometimes segfaults, exit 139) — the result is nondeterministic across runs but consistently wrong. Deterministically wrong across repeated runs in practice.

Expected

6

(matches PHP: 1 + 2 + 1 + 2)

Notes / scope

  • The trigger is a mixed-promoted array that is grown further after promotion inside a loop, then iterated and consumed. A single-shot build ($a = []; $a[] = 1; $a[] = 2.0; then iterate) works; a literal [1, 2.0, 1, 2.0] works. The corruption appears when the promoted array is repeatedly appended-to across for iterations and later iterated with per-element consumption (intval($v), (int)$v, $sum += $v).
  • The symptom is heap free-list corruption (wrong/empty output, or SIGSEGV in __rt_heap_alloc), so it is an ownership/refcount problem in the array_to_mixed promotion + subsequent array_push + foreach value lifetime, not a codegen arithmetic bug.
  • Surfaced while reviewing the enum from(mixed) work (Backed-enum from()/tryFrom() reject a Mixed argument (untyped param / foreach value) at compile time #449): an int-backed Enum::from($v) over such an array crashes, but the crash reproduces identically with intval($v) and no enum, confirming it is orthogonal to enums.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions