Skip to content

Reassigning the catch variable to a new object leaks: previous-value release mistyped as Mixed #479

Description

@mirchaemanuel

Summary

Reassigning the caught exception variable to a new object inside the catch body leaks both objects: the release of the previous slot value is typed as Mixed even though the slot holds an Object, so the decref misreads the pointer as a boxed Mixed cell and becomes a no-op.

Verified on

main (macOS ARM64), via --heap-debug. The #448 fix (PR #477) is neutral on this shape — identical leak counts before and after.

Minimal reproduction

<?php
for ($n = 0; $n < 50; $n++) {
    try { throw new TypeError("x"); } catch (\Throwable $e) {
        $e = new TypeError("y");   // object reassignment
    }
}
echo "done";

Actual (--heap-debug)

HEAP DEBUG: leak summary: live_blocks=149 live_bytes=6760

~3 blocks leak per iteration (the thrown object, the reassigned object, plus an auxiliary block). In the EIR (--emit-ir), the release before the store loads the slot as php=mixed:

v9: Heap(Mixed) php=mixed = load_local slot[0]   ; the slot's declared type is Object("Throwable")
release v9                                        ; decref-as-Mixed on an object pointer → no-op

Controls (work)

  • $e = null; in the catch → clean.
  • unset($e); in the catch → clean.
  • Reassigning an ordinary object local ($o = new T(); $o = new T();) in a loop → clean.

Notes

The mistyped load suggests the assignment's release-previous path falls back to Mixed for catch-bound locals specifically (the ordinary-local path resolves the declared slot type). Distinct from #448 (the missing release of the binding), which is fixed in #477.

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