Skip to content

Commit 2cbdc03

Browse files
authored
Merge pull request #1396 from goblint/issue-1374-2
Avoid base invariant fallback not understood message on reflexive pointer literal equality
2 parents dd8e25e + 0c72199 commit 2cbdc03

File tree

1 file changed

+29
-23
lines changed

1 file changed

+29
-23
lines changed

src/analyses/baseInvariant.ml

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,16 @@ struct
115115
let invariant_fallback ctx st exp tv =
116116
(* We use a recursive helper function so that x != 0 is false can be handled
117117
* as x == 0 is true etc *)
118-
let rec helper (op: binop) (lval: lval) (value: VD.t) (tv: bool): (lval * VD.t) option =
118+
let rec helper (op: binop) (lval: lval) (value: VD.t) (tv: bool): [> `Refine of lval * VD.t | `NotUnderstood] =
119119
match (op, lval, value, tv) with
120120
(* The true-branch where x == value: *)
121121
| Eq, x, value, true ->
122122
if M.tracing then M.tracec "invariant" "Yes, %a equals %a" d_lval x VD.pretty value;
123123
(match value with
124124
| Int n ->
125125
let ikind = Cilfacade.get_ikind_exp (Lval lval) in
126-
Some (x, Int (ID.cast_to ikind n))
127-
| _ -> Some(x, value))
126+
`Refine (x, Int (ID.cast_to ikind n))
127+
| _ -> `Refine (x, value))
128128
(* The false-branch for x == value: *)
129129
| Eq, x, value, false -> begin
130130
match value with
@@ -134,26 +134,26 @@ struct
134134
(* When x != n, we can return a singleton exclusion set *)
135135
if M.tracing then M.tracec "invariant" "Yes, %a is not %a" d_lval x GobZ.pretty n;
136136
let ikind = Cilfacade.get_ikind_exp (Lval lval) in
137-
Some (x, Int (ID.of_excl_list ikind [n]))
138-
| None -> None
137+
`Refine (x, Int (ID.of_excl_list ikind [n]))
138+
| None -> `NotUnderstood
139139
end
140140
| Address n -> begin
141141
if M.tracing then M.tracec "invariant" "Yes, %a is not %a" d_lval x AD.pretty n;
142142
match eval_rv_address ~ctx st (Lval x) with
143143
| Address a when AD.is_definite n ->
144-
Some (x, Address (AD.diff a n))
144+
`Refine (x, Address (AD.diff a n))
145145
| Top when AD.is_null n ->
146-
Some (x, Address AD.not_null)
146+
`Refine (x, Address AD.not_null)
147147
| v ->
148148
if M.tracing then M.tracec "invariant" "No address invariant for: %a != %a" VD.pretty v AD.pretty n;
149-
None
149+
`NotUnderstood
150150
end
151-
(* | Address a -> Some (x, value) *)
151+
(* | Address a -> `Refine (x, value) *)
152152
| _ ->
153153
(* We can't say anything else, exclusion sets are finite, so not
154154
* being in one means an infinite number of values *)
155155
if M.tracing then M.tracec "invariant" "Failed! (not a definite value)";
156-
None
156+
`NotUnderstood
157157
end
158158
| Ne, x, value, _ -> helper Eq x value (not tv)
159159
| Lt, x, value, _ -> begin
@@ -166,10 +166,10 @@ struct
166166
match limit_from n with
167167
| Some n ->
168168
if M.tracing then M.tracec "invariant" "Yes, success! %a is not %a" d_lval x GobZ.pretty n;
169-
Some (x, Int (range_from n))
170-
| None -> None
169+
`Refine (x, Int (range_from n))
170+
| None -> `NotUnderstood
171171
end
172-
| _ -> None
172+
| _ -> `NotUnderstood
173173
end
174174
| Le, x, value, _ -> begin
175175
match value with
@@ -181,16 +181,16 @@ struct
181181
match limit_from n with
182182
| Some n ->
183183
if M.tracing then M.tracec "invariant" "Yes, success! %a is not %a" d_lval x GobZ.pretty n;
184-
Some (x, Int (range_from n))
185-
| None -> None
184+
`Refine (x, Int (range_from n))
185+
| None -> `NotUnderstood
186186
end
187-
| _ -> None
187+
| _ -> `NotUnderstood
188188
end
189189
| Gt, x, value, _ -> helper Le x value (not tv)
190190
| Ge, x, value, _ -> helper Lt x value (not tv)
191191
| _ ->
192192
if M.tracing then M.trace "invariant" "Failed! (operation not supported)";
193-
None
193+
`NotUnderstood
194194
in
195195
if M.tracing then M.traceli "invariant" "assume expression %a is %B" d_exp exp tv;
196196
let null_val (typ:typ):VD.t =
@@ -199,7 +199,7 @@ struct
199199
| TEnum({ekind=_;_},_)
200200
| _ -> Int (ID.of_int (Cilfacade.get_ikind typ) Z.zero)
201201
in
202-
let rec derived_invariant exp tv =
202+
let rec derived_invariant exp tv: [`Refine of lval * VD.t | `NothingToRefine | `NotUnderstood] =
203203
let switchedOp = function Lt -> Gt | Gt -> Lt | Le -> Ge | Ge -> Le | x -> x in (* a op b <=> b (switchedOp op) b *)
204204
match exp with
205205
(* Since we handle not only equalities, the order is important *)
@@ -216,10 +216,13 @@ struct
216216
if VD.is_safe_cast t1 (Cilfacade.typeOfLval x) then
217217
derived_invariant (BinOp (op, Lval x, rval, typ)) tv
218218
else
219-
None
220-
| _ -> None)
219+
`NotUnderstood
220+
| _ -> `NotUnderstood)
221221
| BinOp(op, rval, CastE (TInt (_, _) as ti, Lval x), typ) ->
222222
derived_invariant (BinOp (switchedOp op, CastE(ti, Lval x), rval, typ)) tv
223+
| BinOp(op, (Const _ | AddrOf _), rval, typ) ->
224+
(* This is last such that we never reach here with rval being Lval (it is swapped around). *)
225+
`NothingToRefine
223226
(* Cases like if (x) are treated like if (x != 0) *)
224227
| Lval x ->
225228
(* There are two correct ways of doing it: "if ((int)x != 0)" or "if (x != (typeof(x))0))"
@@ -228,12 +231,15 @@ struct
228231
| UnOp (LNot,uexp,typ) -> derived_invariant uexp (not tv)
229232
| _ ->
230233
if M.tracing then M.tracec "invariant" "Failed! (expression %a not understood)" d_plainexp exp;
231-
None
234+
`NotUnderstood
232235
in
233236
match derived_invariant exp tv with
234-
| Some (lval, value) ->
237+
| `Refine (lval, value) ->
235238
refine_lv_fallback ctx st lval value tv
236-
| None ->
239+
| `NothingToRefine ->
240+
if M.tracing then M.traceu "invariant" "Nothing to refine.";
241+
st
242+
| `NotUnderstood ->
237243
if M.tracing then M.traceu "invariant" "Doing nothing.";
238244
M.debug ~category:Analyzer "Invariant failed: expression \"%a\" not understood." d_exp exp;
239245
st

0 commit comments

Comments
 (0)