Skip to content

Rewrite base pointer refinement by pointee using trick from set#1983

Draft
sim642 wants to merge 1 commit intomasterfrom
issue-1967
Draft

Rewrite base pointer refinement by pointee using trick from set#1983
sim642 wants to merge 1 commit intomasterfrom
issue-1967

Conversation

@sim642
Copy link
Copy Markdown
Member

@sim642 sim642 commented Apr 8, 2026

Issue #1967.

#1531 refactors base set from its current trick to a more natural join.
The trick is to write sequentially to all the targets and if the points-to set is ambiguous, also join with the pre-state.

In light of #1967, this is dual: it refactors the natural join in refinement with the same kind of trick.
The trick is to refine sequentially all the targets and if the points-to set is ambiguous, also join with the pre-state.
Additionally to handle the cases from #1531, the subset of targets is collected which are not contradictory and the pointer is refined to that set.

It passes all our tests (including the cases from #1531) but I haven't though about whether this is actually correct.

There's still one join on the entire local state map, but that's better than one for each target. Maybe that's good enough: at least it seems to have been for set so far.

Copilot AI review requested due to automatic review settings April 8, 2026 13:23
@sim642 sim642 added cleanup Refactoring, clean-up performance Analysis time, memory usage analyze-that labels Apr 8, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors baseInvariant refinement for pointer dereferences to avoid costly full-state joins by using a sequential “set-trick”-style refinement and (attempted) pointee-set filtering for ambiguous pointers, in response to allocation issues discussed in #1967.

Changes:

  • Reworks refine_lv for Mem (Lval lv) to refine pointees sequentially instead of joining per-target states.
  • Tracks a subset of non-contradictory targets and attempts to refine the pointer to that subset.
  • Joins with the pre-state when the (refined) points-to set remains ambiguous.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 124 to 139
@@ -132,16 +132,26 @@ struct
let old_val = map_oldval old_val (Cilfacade.typeOfLval x) in
let v = apply_invariant ~old_val ~new_val:c' in
if is_some_bot v then
Some (D.join acc (try contra st with Analyses.Deadcode -> D.bot ()))
Some (st, ad) (* TODO: some contra thing? *)
else (
if M.tracing then M.tracel "inv" "improve lval %a from %a to %a (c = %a, c' = %a)" d_lval x VD.pretty old_val VD.pretty v pretty c VD.pretty c';
Some (D.join acc (set' x v st))
Some (set' x v st, AD.add base_a ad)
)
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

The per-target refinement case no longer constrains the pointer lval lv to the current base_a before calling set' x v ... (the old set' lv lval_a st is commented out). As a result, set' x v will re-evaluate x with the original (potentially ambiguous) points-to set and can update multiple/all targets with a v computed for just one base_a, which breaks the intended “join over cases” semantics. Reintroduce per-case pointer restriction (or directly set the concrete orig address derived from base_mval + original_offset) so each iteration only refines the corresponding target.

Copilot uses AI. Check for mistakes.
Comment on lines 120 to 133
@@ -132,16 +132,26 @@ struct
let old_val = map_oldval old_val (Cilfacade.typeOfLval x) in
let v = apply_invariant ~old_val ~new_val:c' in
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This fold now threads the accumulating refined state through iterations and uses it for get_mval/apply_invariant. That makes the computed refinement for later base_as depend on earlier refinements (order-dependent) even though the intended semantics is a join over independent per-target refinements from the same pre-state. Consider computing old_val (and the resulting v) from the original pre-state st, and only applying updates to the accumulator, to avoid unsound over-refinement / spurious Deadcode.

Copilot uses AI. Check for mistakes.
BatOption.map_default_delayed (fun d -> if D.is_bot d then raise Analyses.Deadcode else d) default res
BatOption.map_default_delayed (fun (d, ad) ->
if AD.is_bot ad then
raise Analyses.Deadcode
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

Dead-code handling here bypasses Eval.contra: when ad is bottom it unconditionally raises Analyses.Deadcode, and when is_some_bot v it just skips the case. But contra is explicitly parameterized to support modes where contradictions must not kill the state (e.g., unassume uses contra st = st). Please use contra (or join with contra st as appropriate) instead of hard-raising Deadcode so behavior stays consistent across instantiations of this functor.

Suggested change
raise Analyses.Deadcode
contra st

Copilot uses AI. Check for mistakes.
else (
let d = set' lv (Address ad) d in
if AD.cardinal ad > 1 then
D.join st d
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

let d = set' lv (Address ad) d followed by if AD.cardinal ad > 1 then D.join st d will typically undo any refinement of lv to the filtered target set (D.join with the pre-state restores the original pointer value via join/union). If the goal is to refine lv to the non-contradictory subset even in the ambiguous case, consider performing the join in a way that preserves the pointer restriction (e.g., join for pointee updates but meet/overwrite lv afterwards, or otherwise avoid reintroducing eliminated targets).

Suggested change
D.join st d
let d = D.join st d in
set' lv (Address ad) d

Copilot uses AI. Check for mistakes.
@michael-schwarz michael-schwarz self-requested a review April 9, 2026 04:43
@sim642 sim642 marked this pull request as draft April 9, 2026 07:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analyze-that cleanup Refactoring, clean-up performance Analysis time, memory usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants