@@ -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