Skip to content

fix: free owners at the branch exit even when an arm returns (I-182) - #147

Merged
artefactop merged 1 commit into
mainfrom
fix/i-182-owner-free-conditional-last-use-leak
Sep 16, 2026
Merged

artefactop merged 1 commit into
mainfrom
fix/i-182-owner-free-conditional-last-use-leak

Conversation

@artefactop

@artefactop artefactop commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes I-182: an owner whose last read sits inside a conditional arm leaked its heap buffer on every not-taken path whenever the branch (or a sibling arm) could return. The conditional-last-use re-anchor refused may-return branches and kept the in-arm anchor — which never fires on paths that skip the arm:

  • Last use in an arm that returns → the fall-through path reached the function end with the owner live (64 B/call; 33 MB peak RSS over 500k calls, now flat at 1 MB).
  • Last use in a fall-through arm with a returning sibling → the implicit-else path reached the merge with the owner live (same leak).

Fix: drop the may-return refusal in the re-anchor (both Inst and Param owners), so the Free always anchors at the branch exit — the earliest point where the value is dead on all fall-through paths. The refusal predated the owner return epilogue, which owns the return paths: its covered-check excludes ancestor branches, so a branch-exit anchor never suppresses the epilogue Free, and the epilogue never double-fires on paths the exit anchor covers. No codegen changes.

Test plan

  • cargo test --workspace — green (incl. 2 new behavioral tests: both arm shapes, taken + not-taken + sibling paths)
  • ./scripts/run_linux_tests.sh (Docker) — ASan 36/36, Valgrind 41/41, including 2 new fixtures (last_use_in_returning_arm_fallthrough, last_use_in_fallthrough_arm_sibling_returns) and the pre-existing last_use_in_if_fallthrough / conditional-move fixtures the issue called out
  • RSS oracle on both leak shapes (500k calls): 33 MB peak → 1 MB flat
  • RUSTFLAGS=-Dwarnings cargo clippy --workspace --all-targets, cargo fmt --check — clean

Summary by CodeRabbit

  • Bug Fixes

    • Fixed potential memory leaks when the final use of an owned value occurs inside conditional branches, including branches that return or fall through.
    • Ensured heap-allocated string values are released correctly across all conditional execution paths.
  • Tests

    • Added integration, AddressSanitizer, and Valgrind coverage for conditional branch cleanup and leak detection.

@coderabbitai

coderabbitai Bot commented Sep 15, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: ab51a860-d74b-40d6-80fe-fe0c2d9fdb95

📥 Commits

Reviewing files that changed from the base of the PR and between 237469d and 619b9f7.

📒 Files selected for processing (6)
  • ISSUES.md
  • ryo-frontend/src/ownership/mod.rs
  • ryo/tests/asan_smoke.rs
  • ryo/tests/common/mod.rs
  • ryo/tests/integration_ownership.rs
  • ryo/tests/valgrind_smoke.rs
💤 Files with no reviewable changes (1)
  • ISSUES.md

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The ownership pass now anchors conditional last-use frees at branch exits without excluding branches that may return. New fixtures and integration, ASan, and Valgrind tests cover returning-arm and fallthrough-arm cases.

Changes

Ownership leak fix

Layer / File(s) Summary
Branch free anchoring
ryo-frontend/src/ownership/mod.rs, ISSUES.md
Instruction and parameter owners now re-anchor conditional last-use frees without the branch_may_not_return guard. The corresponding issue entry was removed.
Ownership regression fixtures
ryo/tests/common/mod.rs, ryo/tests/integration_ownership.rs
Two fixtures and integration tests cover last uses in returning arms and fallthrough arms with sibling returns.
Leak detection coverage
ryo/tests/asan_smoke.rs, ryo/tests/valgrind_smoke.rs
ASan and Valgrind smoke tests run both new fixtures.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Merge Risk: ⚪ Minimal · up to 619b9

The conditional ownership cleanup change has regression and leak-detection coverage, and no actionable current-head risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: freeing owners at branch exit when an arm returns. It is concise, specific, and includes the related issue identifier.
Docstring Coverage ✅ Passed Docstring coverage is 91.67% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 functions across 5 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/i-182-owner-free-conditional-last-use-leak

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Base automatically changed from fix/i-176-borrowed-param-promotion-leak to main September 16, 2026 16:46
The conditional-last-use re-anchor refused branches that may return,
keeping the in-arm anchor so the return path stayed covered. But the
in-arm anchor never fires on not-taken paths: an owner whose last
read sits inside a returning arm leaked its buffer on every other
path (steady 33 MB RSS growth over 500k calls, now flat), whether
that path fell through to the function end or took a non-returning
sibling arm.

The refusal predates the owner return epilogue, which covers the
return paths: its covered-check excludes ancestor branches, so a
branch-exit anchor does not suppress the epilogue Free. Drop the
refusal for both Inst and Param owners — the Free anchors at the
branch exit on every fall-through path, and the epilogue fires on
every return path.

Regression coverage: two behavioral tests plus Valgrind/ASan fixtures
for both arm shapes (last use in the returning arm; last use in a
fall-through arm with a returning sibling).
@artefactop
artefactop force-pushed the fix/i-182-owner-free-conditional-last-use-leak branch from ffae476 to 619b9f7 Compare September 16, 2026 16:55
@codspeed

codspeed Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 45 untouched benchmarks


Comparing fix/i-182-owner-free-conditional-last-use-leak (619b9f7) with main (237469d)

Open in CodSpeed

@artefactop

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Sep 16, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@artefactop
artefactop merged commit 250f898 into main Sep 16, 2026
15 checks passed
@artefactop
artefactop deleted the fix/i-182-owner-free-conditional-last-use-leak branch September 16, 2026 22:39
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.

1 participant