Skip to content

Give a loop no unchecked half over a local whose block has closed - #3709

Merged
tamnd merged 2 commits into
mainfrom
safety/room-of-a-gone-local
Oct 16, 2026
Merged

tamnd merged 2 commits into
mainfrom
safety/room-of-a-gone-local

Conversation

@tamnd

@tamnd tamnd commented Oct 16, 2026

Copy link
Copy Markdown
Owner

The "what the elimination took out" job has failed on main for a while with one problem: a-pointer-to-a-block-scope-local-followed-in-another-file-after-the-block gives no report at -O2 and exits 0. It is refused at -O0 and -O1. Building main at -O2 and follow at -O0 is still refused, and the other way round is not, so the miss is in the -O2 build of follow.

That loop is split in two at -O2. __rucc_extent says how many bytes the object has from the pointer on, the loop runs that far with no check in it, and the rest runs with every check. For a named object (a local or a global) the answer comes from room, which looks at the capability's bounds and nothing else. The half with no check has no liveness check either, so a write through a pointer to a buffer whose block had closed ran unchecked, and the __rucc_check_live that refuses it at -O0 is only in the other half.

room now gives zero for a local whose frame returned or whose block closed, by the same witness live asks. The whole loop then runs checked, and its first access is refused as J1. A capability that is not named still goes to the planes as before, and a freed heap block was never a question for room.

The runtime test for a returned frame now also checks that room gives the full sixteen bytes before the frame closes and zero after.

Checked on the Linux box: cargo test -p rucc-safe-rt (422 tests) passes and clippy with -D warnings is clean. cargo xtask accounting gives 208 programs compared with 0 divergences and 0 problems, where main has the one above. cargo xtask safety gives 116 refused and 90 silent, the same as main.

At -O2 a loop over a named object is split where __rucc_extent says the object ends, and the half before that runs with no check in it. room() answered from the capability's bounds alone, so a loop writing through a pointer to a buffer whose block had closed ran unchecked, and the liveness check the build with every check makes never ran. room() now answers zero for a local whose frame returned or whose block closed, so the whole loop runs checked and its first access is refused.
@tamnd tamnd added kind/bug Crash, wrong diagnostic, or a valid program rejected area/safety The run-time memory safety monitor, its planes, and its runtime labels Oct 16, 2026
@tamnd
tamnd merged commit 96712e5 into main Oct 16, 2026
@tamnd
tamnd deleted the safety/room-of-a-gone-local branch October 16, 2026 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/safety The run-time memory safety monitor, its planes, and its runtime kind/bug Crash, wrong diagnostic, or a valid program rejected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant