Skip to content

Rebinding a loop-grown array local after pushing it into an outer array leaks one block per rebind #528

Description

@mirchaemanuel

Summary

Rebinding a loop-grown array local to [] after pushing it into an outer array leaks exactly one 40-byte block per rebind (N outer iterations → N−1 leaked blocks). The output is correct; only memory is lost.

Environment

  • elephc main e63d5d337 (v0.26.0-158), macOS arm64 (Apple Silicon); PHP 8.4.23 as behavioral reference.

Repro

<?php
$a = [];
for ($i = 0; $i < 6; $i++) {
    $mid = [];
    for ($j = 0; $j < 3; $j++) { $mid[] = ['x', 'y']; }
    $a[] = $mid;
}
echo count($a) . "\n";
elephc --heap-debug bisect_b.php && ./bisect_b

Observed

6
HEAP DEBUG: leak summary: live_blocks=5 live_bytes=200

Scaling law (measured): N outer iterations → N−1 leaked blocks, 40 bytes each. 3 iters → live_blocks=2 live_bytes=80; 6 → 5/200; 10 → allocs=154 frees=145 live_blocks=9 live_bytes=360.

What is required to trigger it (negative results, all clean on pristine main)

  • a single outer iteration (no rebind): clean;
  • an inner loop with exactly one push ($mid = []; $mid[] = ['x','y'];): clean;
  • assigning a literal instead of growing ($mid = [['x','y']];): clean.

The leak needs all three of: an inner grow loop with ≥ ~3 pushes into $mid (enough to force a storage reallocation), then $a[] = $mid, then rebinding $mid = [] on the next outer iteration — one stale block survives per rebind event.

Expected

Leak-free: after $a[] = $mid transfers/retains the final storage, the $mid = [] reassignment should release everything the local still owns.

Notes

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