Skip to content

fix(runtime): caller() must not zero out invocant when @_ is shifted (GH-1682) - #1698

Merged
fglock merged 1 commit into
masterfrom
fix/1682-caller-corrupts-invocant
Oct 8, 2026
Merged

fglock merged 1 commit into
masterfrom
fix/1682-caller-corrupts-invocant

Conversation

@fglock

@fglock fglock commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes #1682 — Math::BigInt mbimbf.t and trap.t failures for Math::BigFloat.

  • Root cause: RuntimeArray.get() was calling recordLocalArrayOwner(@_, index) on aliased arrays like @_. When a method called $_[0]->some_method() before shift @_, this overwrote the element's localArrayOwner to point at @_. Later, Carp::croak → caller() → clearStaleLocalArrayAliases() detected the element as stale (no longer in @_ after the shift) and called clearForArraySlotRemoval() on it — which zeroed out the original caller's variable (e.g. $x).

  • Fix: In RuntimeArray.get(), only call recordLocalArrayOwner() when elementsOwned == true. Aliased arrays like @_ set elementsOwned = false (via setFromListAliased), so their elements' canonical array-slot tracking is never overwritten.

  • Regression test: unit/method_custom_isa_caller_preservation.t — directly reproduces the pattern (method call on $_[0] before shift + Carp::croak).

Test plan

  • New unit test unit/method_custom_isa_caller_preservation.t passes (all 5 functional tests ok)
  • Existing unit/caller_db_args_freed.t still passes (verified clearStaleLocalArrayAliases still works correctly for the @values aliasing case)
  • src/test/resources/module/Math-BigInt/t/trap.t — tests 37, 41, 43, 45 (previously not ok for Math::BigFloat) now pass
  • make passes (shard failures are pre-existing: apostrophe_package_separator_feature.t isolation issue and PerlOnJavaHomeIntegrationTest JAR packaging issue, both unrelated to this change)

🤖 Generated with Claude Code

)

When a method accesses $_[0] (e.g. `$_[0]->isa(...)`) before calling
`shift @_`, RuntimeArray.get() was calling recordLocalArrayOwner(@_, 0)
on the caller's scalar. This overwrote the element's localArrayOwner to
point at @_. Later, when Carp::croak called caller() which called
clearStaleLocalArrayAliases() on the pristine args snapshot, the element
was detected as stale (no longer at index 0 of @_ after the shift) and
clearForArraySlotRemoval() was called on it — zeroing out the caller's
original variable.

The fix: in RuntimeArray.get(), only call recordLocalArrayOwner() when
the array owns its elements (elementsOwned == true). Aliased arrays like
@_ borrow scalars from the caller without owning them; recording @_ as
the owner here corrupts the stale-alias detection for the caller's
variable.

This preserves the existing behaviour of caller_db_args_freed.t, which
relies on clearStaleLocalArrayAliases() correctly clearing an element
whose owner (@values) was emptied after the call.

Adds regression test: unit/method_custom_isa_caller_preservation.t

Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@fglock
fglock merged commit 5287a45 into master Oct 8, 2026
2 checks passed
@fglock
fglock deleted the fix/1682-caller-corrupts-invocant branch October 8, 2026 14:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Math-BigInt bundled mbimbf.t and trap.t failures

1 participant