fix(ir): write nested array assignments through the parent cell (#529)#553
Merged
nahime0 merged 4 commits intoJul 18, 2026
Merged
Conversation
…galstudio#529) Nested assignments ($a[$i][$j] = ...) lowered the FULL target as a read and replaced the resulting Mixed cell in place. __rt_mixed_array_get returns a detached fresh box whenever the slot storage is not already a boxed Mixed cell (string/int/float slots of a concrete inner array), so the replacement mutated a temporary: the write was silently lost and the replacement payload leaked. When the slot WAS a boxed cell the write landed, but the retained cell returned by the read was never released. Lower the statement by splitting off the innermost key instead: the parent chain is read as before, and the write goes through the three-operand RuntimeCall (__rt_mixed_array_set for Mixed parents, offsetSet for ArrayAccess objects), which mutates the container aliased by the parent cell for every slot representation. Owned intermediate boxes of deeper chains are released after the write. Claude-Session: https://claude.ai/code/session_01QyzntRke1Cgxgq1ueuz4X9
Member
|
Follow-up #555 now tracks the missing-intermediate case: a write such as That is distinct from #529/#553's existing-parent fix, so it does not need to broaden this PR. The issue also records the related 3+ level concrete-homogeneous-intermediate limitation documented here, since both likely need the same in-place promotion/fetch-for-write infrastructure. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(ir): write nested array assignments through the parent cell (#529)
Fixes #529.
Symptom
The nested write into an
Array(Mixed)element — the only nested-write shape the checker accepts for plain arrays — was silently dropped, with a small heap leak per write.Root cause (two stacked defects)
StmtKind::NestedArrayAssignlowered the full target as a read and then replaced the resulting Mixed cell in place (two-operandOp::RuntimeCall→ the mixed-cell replacement path):__rt_mixed_array_getreturns a detached fresh box whenever the slot storage is not already a boxed Mixed cell (string/int/float slots of a concrete homogeneous inner array —mixed_array_get.rsboxes those through__rt_mixed_from_value). The in-place cell replacement then mutated a temporary that nothing stores back: the write was lost and the replacement payload leaked (the 2 leaked blocks: fresh cell + persisted string).__rt_incref); the write landed, but the retained cell was never released — one block leaked per write.Fix
Split off the innermost key in
lower_nested_array_assigninstead of reading the full target: the parent chain is lowered as before, and the write goes through the three-operandOp::RuntimeCall—__rt_mixed_array_setfor Mixed parents,offsetSetdispatch for ArrayAccess objects. That helper mutates the container aliased by the parent cell and handles every slot representation (including COW split and representation conversion, publishing the new pointer back into the parent cell). Owned intermediate boxes of deeper chains are released after the write; string key/value operands follow the samerelease_persisted_string_operandrules as the existing$mixed[$k] = $vpath.For ArrayAccess object parents this also means the write now goes through
offsetSet(PHP semantics) instead of a cell replacement on theoffsetGetresult.Tests
tests/codegen/arrays/nested_mixed_write.rs, 7 regression tests (all failing before the fix, all heap-clean after):$a[0][1] .= '!')Residual limitation (pre-existing, documented in the test header)
A 3+ level chain whose intermediate level is a concrete homogeneous array (raw-pointer slots, e.g.
[[['x', 1]], 7]) still loses the write: the intermediate read boxes a fresh retained cell, the retain makes the leaf look shared, and the write path's__rt_array_to_mixedCOW-splits it. Fixing that shape needs a fetch-for-write read helper that promotes intermediate slots to boxed cells in place — happy to file it as a follow-up issue.QA
patchedwithHEAP DEBUG: leak summary: clean.arrays328,foreach118,spl247,optimizer254,nested140,json444,zval72,mixed252,ir_backend_smoke_test255 — 0 failures.https://claude.ai/code/session_01QyzntRke1Cgxgq1ueuz4X9