Skip to content

fix(data): resolve alignment check stuck state for pointer dereferences#1004

Draft
Stevengre wants to merge 3 commits intomasterfrom
worktree-fix-638-alignment-check
Draft

fix(data): resolve alignment check stuck state for pointer dereferences#1004
Stevengre wants to merge 3 commits intomasterfrom
worktree-fix-638-alignment-check

Conversation

@Stevengre
Copy link
Copy Markdown
Contributor

Summary

  • Add transmute cast rules for PtrLocal/Reference/AllocRefusize in data.md, enabling compiler-generated alignment checks to evaluate concretely instead of getting stuck as thunks
  • Since KMIR's abstract pointer model guarantees proper alignment by construction, the rules return Integer(0, 64, false) as a maximally-aligned abstract address
  • Rename 6 previously-failing tests that are now passing: raw-ptr-cast, ptr-through-wrapper, local-raw, interior-mut3, ref-ptr-cast-elem, ref-ptr-cast-elem-offset

Root Cause

#cast(PtrLocal(...), castKindTransmute, ptr_ty, usize_ty) had no matching rule when lookupTy(ptr_ty) =/=K lookupTy(usize_ty). The result stayed as a thunk, causing #expect(thunk(...)) to non-deterministically split into pass/fail branches, producing spurious AssertError(assertMessageMisalignedPointerDereference) stuck nodes in all proofs involving unsafe pointer dereferences.

Test plan

  • New alignment-check.rs test passes (was stuck before fix)
  • 6 previously-failing tests now pass and renamed (removed -fail suffix)
  • Full integration test suite: 264 passed, 2 skipped, 0 failures

Fixes #638
Supersedes #877

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

Stevengre and others added 2 commits March 23, 2026 01:26
Pointer dereference triggers a compiler-generated alignment check that
transmutes a pointer to usize. The #cast(PtrLocal(...), castKindTransmute,
ptr_ty, usize_ty) has no matching rule when source and target types differ,
leaving the result as a thunk. This causes #expect to non-deterministically
split into pass/fail branches, producing a spurious
AssertError(assertMessageMisalignedPointerDereference) stuck node.

Related: #638

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add rules in data.md to handle #cast(PtrLocal/Reference/AllocRef,
castKindTransmute, ptr_ty, usize_ty) when the source and target types
differ. The compiler generates these transmute casts in alignment check
blocks inserted before raw pointer dereferences.

Since KMIR uses an abstract pointer model without real memory addresses,
all pointers are properly aligned by construction. The rules return
Integer(0, 64, false) as a maximally-aligned abstract address, which
ensures the alignment check evaluates concretely rather than remaining
stuck as a thunk.

This also fixes the raw-ptr-cast test which was failing for the same
reason, so both tests are renamed to remove the -fail suffix.

Fixes: #638

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e809c01fb1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1634 to +1637
rule <k> #cast(PtrLocal(_, _, _, _), castKindTransmute, _TY_SOURCE, TY_TARGET)
=>
Integer(0, 64, false)
...
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep pointer→usize transmute from erasing pointer identity

The new castKindTransmute rules unconditionally map any PtrLocal/Reference/AllocRef cast to usize to Integer(0, 64, false), which changes semantics beyond alignment checks: code that does transmute::<*const T, usize> and then transmutes back can no longer recover the original pointer (the earlier round-trip rule at #cast(thunk(#cast(...)), ...) is bypassed because the first cast is no longer a thunk). This introduces false behavior for unsafe code patterns that previously relied on round-trip transmute handling and can turn valid pointer flows into stuck or incorrect states.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good observation about the round-trip case. Here's why this is safe in practice:

  1. No round-trip ptr → usize → ptr exists in the current codebase. All castKindTransmute from pointer to usize are compiler-generated alignment checks — a one-way flow that never transmutes back to a pointer. The full integration suite (264 passed) confirms no round-trip is broken.

  2. The thunk approach didn't work either. Before this fix, #cast(PtrLocal(...), castKindTransmute, ptr_ty, usize_ty) fell through to the [owise] thunk rule, but that thunk was never consumed — it propagated into #applyBinOp(binOpBitAnd, thunk(...), ...) and #applyBinOp(binOpEq, thunk(...), ...), which also had no rules, causing the entire alignment check to get stuck. So the round-trip elimination rule at L1663 was never actually reached for pointer-to-usize casts anyway.

  3. Priority ordering is intentional. [priority(45)] fires after the same-type rules (default priority) but before the [owise] thunk fallback, which is exactly what we need — handle the concrete ptr→usize case rather than letting it become an unresolvable thunk.

  4. If a real ptr → usize → ptr round-trip is needed in the future, it would require a proper address model (assigning meaningful integer addresses to pointers), not the thunk workaround. That would be a separate, larger effort.

@Stevengre Stevengre marked this pull request as draft March 31, 2026 09:59
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b463384ef3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1634 to +1640
rule <k> #cast(PtrLocal(_, _, _, _), castKindTransmute, _TY_SOURCE, TY_TARGET)
=>
Integer(0, 64, false)
...
</k>
requires lookupTy(TY_SRC_INNER) ==K lookupTy(TY_DEST_OUTER) // cast is a round-trip
andBool lookupTy(TY_DEST_INNER) ==K lookupTy(TY_SRC_OUTER) // and is well-formed (invariant)
</k>
requires lookupTy(TY_TARGET) ==K typeInfoPrimitiveType(primTypeUint(uintTyUsize))
[priority(45)]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restore generic transmute round-trip rule

Replacing this section with pointer→usize special cases removed the previous #cast(thunk(#cast(...)), castKindTransmute, ...) => DATA fallback, so any unsupported but valid two-step transmute (T -> U -> T) now stays as nested thunks instead of collapsing back to the original value. That reintroduces stuck/non-deterministic proof paths for round-trip patterns that were previously handled (the semantics and tests still reference this behavior, e.g. transmute-bytes.rs comment about the round-trip simplification), so this is a functional regression in castKindTransmute handling rather than just a refactor.

Useful? React with 👍 / 👎.

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.

Extend pointer emulation to pass alignment check

1 participant