Skip to content

Commit 582608c

Browse files
authored
Merge pull request #1962 from goblint/int-predicates
Simplify return type of int domain comparison predicates
2 parents a13b7e1 + 219cd77 commit 582608c

18 files changed

Lines changed: 254 additions & 205 deletions

src/analyses/base.ml

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,11 @@ struct
169169

170170
let iDtoIdx x = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) x (* TODO: proper castkind *)
171171

172+
let id_binary_pred result_ik f x y =
173+
match f x y with
174+
| Some b -> ID.of_bool result_ik b
175+
| None -> ID.of_interval result_ik (Z.zero, Z.one)
176+
172177
(** Unary float predicates return non-zero for [true].
173178
@see C11 7.12.3 *)
174179
let fd_unary_pred = function
@@ -180,7 +185,7 @@ struct
180185
@see C11 7.12.14, 6.5.8, 6.5.9 *)
181186
let fd_binary_pred = function
182187
| Some b -> ID.of_bool IInt b
183-
| None -> ID.top_of IInt
188+
| None -> ID.of_interval IInt (Z.zero, Z.one)
184189

185190
let unop_ID = function
186191
| Neg -> ID.neg
@@ -235,17 +240,17 @@ struct
235240
| `Neq ->
236241
Checks.safe Checks.Category.DivisionByZero);
237242
ID.rem x y
238-
| Lt -> ID.lt
239-
| Gt -> ID.gt
240-
| Le -> ID.le
241-
| Ge -> ID.ge
242-
| Eq -> ID.eq
243+
| Lt -> id_binary_pred result_ik ID.lt
244+
| Gt -> id_binary_pred result_ik ID.gt
245+
| Le -> id_binary_pred result_ik ID.le
246+
| Ge -> id_binary_pred result_ik ID.ge
247+
| Eq -> id_binary_pred result_ik ID.eq
243248
(* TODO: This causes inconsistent results:
244249
def_exc and interval definitely in conflict:
245250
evalint: base eval_rv m -> (Not {0, 1}([-31,31]),[1,1])
246251
evalint: base eval_rv 1 -> (1,[1,1])
247252
evalint: base query_evalint m == 1 -> (0,[1,1]) *)
248-
| Ne -> ID.ne
253+
| Ne -> id_binary_pred result_ik ID.ne
249254
| BAnd -> ID.logand
250255
| BOr -> ID.logor
251256
| BXor -> ID.logxor
@@ -306,7 +311,7 @@ struct
306311
| Some t ->
307312
let f_offset_bytes = Cilfacade.bytesOffsetOnly t (Field (f, NoOffset)) in
308313
let f_offset = IdxDom.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int f_offset_bytes) in
309-
begin match IdxDom.(to_bool (eq f_offset (neg n_offset))) with
314+
begin match IdxDom.(eq f_offset (neg n_offset)) with
310315
| Some true -> `NoOffset
311316
| _ -> `Field (f, `Index (n_offset, `NoOffset))
312317
end
@@ -2388,10 +2393,10 @@ struct
23882393
let casted_n = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) n in (* TODO: proper castkind *)
23892394
let ds_eq_n =
23902395
begin try ID.eq casted_ds casted_n
2391-
with IntDomain.ArithmeticOnIntegerBot _ -> ID.top_of @@ Cilfacade.ptrdiff_ikind ()
2396+
with IntDomain.ArithmeticOnIntegerBot _ -> None
23922397
end
23932398
in
2394-
Option.default false (ID.to_bool ds_eq_n)
2399+
Option.default false ds_eq_n
23952400
| _ -> false
23962401
in
23972402
let dest_a, dest_typ = addr_type_of_exp dst in

src/analyses/baseInvariant.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,8 @@ struct
329329
* However, a%b will give [-b+1, b-1] for a=top, but we only want the positive/negative side depending on the sign of c*b.
330330
* If c*b = 0 or it can be positive or negative, we need the full range for the remainder. *)
331331
let rem =
332-
let is_pos = ID.to_bool @@ ID.gt (ID.mul b c) (ID.of_int ikind Z.zero) = Some true in
333-
let is_neg = ID.to_bool @@ ID.lt (ID.mul b c) (ID.of_int ikind Z.zero) = Some true in
332+
let is_pos = ID.gt (ID.mul b c) (ID.of_int ikind Z.zero) = Some true in
333+
let is_neg = ID.lt (ID.mul b c) (ID.of_int ikind Z.zero) = Some true in
334334
let full = ID.rem a b in
335335
if is_pos then ID.meet (ID.starting ikind Z.zero) full
336336
else if is_neg then ID.meet (ID.ending ikind Z.zero) full

src/analyses/memOutOfBounds.ml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,12 @@ struct
295295
let one = intdom_of_int 1 in
296296
let casted_es = ID.sub casted_es one in
297297
begin try ID.lt casted_es casted_offs
298-
with IntDomain.ArithmeticOnIntegerBot _ -> ID.bot_of @@ Cilfacade.ptrdiff_ikind ()
298+
with IntDomain.ArithmeticOnIntegerBot _ -> None
299299
end
300300
in
301301
let behavior = Undefined MemoryOutOfBoundsAccess in
302302
let cwe_number = 823 in
303-
begin match ID.to_bool ptr_size_lt_offs with
303+
begin match ptr_size_lt_offs with
304304
| Some true ->
305305
(set_mem_safety_flag InvalidDeref;
306306
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of lval dereference expression is %a (in bytes). It is offset by %a (in bytes). Memory out-of-bounds access must occur" ID.pretty casted_es ID.pretty casted_offs);
@@ -345,7 +345,7 @@ struct
345345
let casted_ps = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) ps in (* TODO: proper castkind *)
346346
let casted_ao = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) ao in (* TODO: proper castkind *)
347347
let ptr_size_lt_offs = ID.lt casted_ps casted_ao in
348-
begin match ID.to_bool ptr_size_lt_offs with
348+
begin match ptr_size_lt_offs with
349349
| Some true ->
350350
set_mem_safety_flag InvalidDeref;
351351
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer is %a (in bytes). It is offset by %a (in bytes) due to pointer arithmetic. Memory out-of-bounds access must occur" ID.pretty casted_ps ID.pretty casted_ao;
@@ -433,7 +433,7 @@ struct
433433
let casted_ps = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) ps in (* TODO: proper castkind *)
434434
let casted_o = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) o in (* TODO: proper castkind *)
435435
let ptr_size_lt_offs = ID.lt casted_ps casted_o in
436-
begin match ID.to_bool ptr_size_lt_offs with
436+
begin match ptr_size_lt_offs with
437437
| Some true ->
438438
set_mem_safety_flag InvalidDeref;
439439
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of pointer in expression %a is %a (in bytes). It is offset by %a (in bytes). Memory out-of-bounds access must occur" d_exp binopexp ID.pretty casted_ps ID.pretty casted_o;
@@ -479,7 +479,7 @@ struct
479479
let casted_en = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) en in (* TODO: proper castkind *)
480480
let casted_ao = ID.cast_to ~kind:Internal (Cilfacade.ptrdiff_ikind ()) addr_offs in (* TODO: proper castkind *)
481481
let dest_size_lt_count = ID.lt casted_ds (ID.add casted_en casted_ao) in
482-
begin match ID.to_bool dest_size_lt_count with
482+
begin match dest_size_lt_count with
483483
| Some true ->
484484
set_mem_safety_flag InvalidDeref;
485485
M.warn ~category:(Behavior behavior) ~tags:[CWE cwe_number] "Size of %a in function %s is %a (in bytes) with an address offset of %a (in bytes). Count is %a (in bytes). Memory out-of-bounds access must occur" d_exp ptr fun_name ID.pretty casted_ds ID.pretty casted_ao ID.pretty casted_en;

src/cdomain/value/cdomains/arrayDomain.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -803,8 +803,8 @@ end
803803
(* This is the main array out of bounds check *)
804804
let array_oob_check ( type a ) (module Idx: IntDomain.Z with type t = a) (x, l) (e, v) =
805805
if GobConfig.get_bool "ana.arrayoob" then (* The purpose of the following 2 lines is to give the user extra info about the array oob *)
806-
let idx_before_end = Idx.to_bool (Idx.lt v l) in (* check whether index is before the end of the array *)
807-
let idx_after_start = Idx.to_bool (Idx.ge v (Idx.of_int (Cilfacade.ptrdiff_ikind ()) Z.zero)) in (* check whether the index is non-negative *)
806+
let idx_before_end = Idx.lt v l in (* check whether index is before the end of the array *)
807+
let idx_after_start = Idx.ge v (Idx.of_int (Cilfacade.ptrdiff_ikind ()) Z.zero) in (* check whether the index is non-negative *)
808808
(* For an explanation of the warning types check the Pull Request #255 *)
809809
match idx_after_start, idx_before_end with
810810
| Some true, Some true -> (* Certainly in bounds on both sides.*)

src/cdomain/value/cdomains/int/bitfieldDomain.ml

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ module BitfieldArith (Ints_t : IntOps.IntOps) = struct
5252

5353
let one = of_int Ints_t.one
5454
let zero = of_int Ints_t.zero
55-
let top_bool = join one zero
5655

5756
let bits_known (z,o) = z ^: o
5857
let bits_invalid (z,o) = !:(z |: o)
@@ -591,34 +590,31 @@ module BitfieldFunctor (Ints_t : IntOps.IntOps): Bitfield_SOverflow with type in
591590

592591
let eq ik x y =
593592
if Z.compare (BArith.max ik x) (BArith.min ik y) <= 0 && Z.compare (BArith.min ik x) (BArith.max ik y) >= 0 then
594-
of_bool ik true
593+
Some true
595594
else if Z.compare (BArith.min ik x) (BArith.max ik y) > 0 || Z.compare (BArith.max ik x) (BArith.min ik y) < 0 then
596-
of_bool ik false
595+
Some false
597596
else
598-
BArith.top_bool
597+
None
599598

600-
let ne ik x y = match eq ik x y with
601-
| t when t = of_bool ik true -> of_bool ik false
602-
| t when t = of_bool ik false -> of_bool ik true
603-
| _ -> BArith.top_bool
599+
let ne ik x y = Option.map not (eq ik x y)
604600

605601
let le ik x y =
606602
if Z.compare (BArith.max ik x) (BArith.min ik y) <= 0 then
607-
of_bool ik true
603+
Some true
608604
else if Z.compare (BArith.min ik x) (BArith.max ik y) > 0 then
609-
of_bool ik false
605+
Some false
610606
else
611-
BArith.top_bool
607+
None
612608

613609
let ge ik x y = le ik y x
614610

615611
let lt ik x y =
616612
if Z.compare (BArith.max ik x) (BArith.min ik y) < 0 then
617-
of_bool ik true
613+
Some true
618614
else if Z.compare (BArith.min ik x) (BArith.max ik y) >= 0 then
619-
of_bool ik false
615+
Some false
620616
else
621-
BArith.top_bool
617+
None
622618

623619
let gt ik x y = lt ik y x
624620

src/cdomain/value/cdomains/int/congruenceDomain.ml

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ struct
124124
let of_int ik (x: int_t) = normalize ik @@ Some (x, Z.zero)
125125
let zero = Some (Z.zero, Z.zero)
126126
let one = Some (Z.one, Z.zero)
127-
let top_bool = top()
128127

129128
let of_bool _ik = function true -> one | false -> zero
130129

@@ -444,48 +443,50 @@ struct
444443
res
445444

446445
let ne ik (x: t) (y: t) = match x, y with
447-
| Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (not (c1 =: c2 ))
448-
| x, y -> if meet ik x y = None then of_bool ik true else top_bool
446+
| Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> Some (not (c1 =: c2))
447+
| x, y -> if meet ik x y = None then Some true else None
449448

450449
let eq ik (x: t) (y: t) = match x, y with
451-
| Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> of_bool ik (c1 =: c2)
452-
| x, y -> if meet ik x y <> None then top_bool else of_bool ik false
450+
| Some (c1, m1), Some (c2, m2) when (m1 =: Z.zero) && (m2 =: Z.zero) -> Some (c1 =: c2)
451+
| x, y -> if meet ik x y <> None then None else Some false
453452

454453
let comparison ik op x y = match x, y with
455-
| None, None -> bot_of ik
454+
| None, None -> None
456455
| None, _ | _, None -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
457456
| Some (c1, m1), Some (c2, m2) ->
458457
if m1 =: Z.zero && m2 =: Z.zero then
459-
if op c1 c2 then of_bool ik true else of_bool ik false
458+
Some (op c1 c2)
460459
else
461-
top_bool
460+
None
462461

463462
let ge ik x y = comparison ik (>=:) x y
464463

464+
let pretty_bool_option = Pretty.docOpt (Pretty.dprintf "%B")
465+
465466
let ge ik x y =
466467
let res = ge ik x y in
467-
if M.tracing then M.trace "congruence" "greater or equal : %a %a -> %a " pretty x pretty y pretty res;
468+
if M.tracing then M.trace "congruence" "greater or equal : %a %a -> %a" pretty x pretty y pretty_bool_option res;
468469
res
469470

470471
let le ik x y = comparison ik (<=:) x y
471472

472473
let le ik x y =
473474
let res = le ik x y in
474-
if M.tracing then M.trace "congruence" "less or equal : %a %a -> %a " pretty x pretty y pretty res;
475+
if M.tracing then M.trace "congruence" "less or equal : %a %a -> %a" pretty x pretty y pretty_bool_option res;
475476
res
476477

477478
let gt ik x y = comparison ik (>:) x y
478479

479480
let gt ik x y =
480481
let res = gt ik x y in
481-
if M.tracing then M.trace "congruence" "greater than : %a %a -> %a " pretty x pretty y pretty res;
482+
if M.tracing then M.trace "congruence" "greater than : %a %a -> %a" pretty x pretty y pretty_bool_option res;
482483
res
483484

484485
let lt ik x y = comparison ik (<:) x y
485486

486487
let lt ik x y =
487488
let res = lt ik x y in
488-
if M.tracing then M.trace "congruence" "less than : %a %a -> %a " pretty x pretty y pretty res;
489+
if M.tracing then M.trace "congruence" "less than : %a %a -> %a" pretty x pretty y pretty_bool_option res;
489490
res
490491

491492
let invariant_ikind e ik x =

src/cdomain/value/cdomains/int/defExcDomain.ml

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ struct
298298
| `Definite x -> Some (IntOps.BigIntOps.to_bool x)
299299
| `Excluded (s,r) when S.mem Z.zero s -> Some true
300300
| _ -> None
301-
let top_bool = `Excluded (S.empty (), (0, 1))
302301

303302
let of_interval ik (x,y) =
304303
if Z.compare x y = 0 then
@@ -392,29 +391,29 @@ struct
392391
(* The equality check: *)
393392
let eq ik x y = match x,y with
394393
(* Not much to do with two exclusion sets: *)
395-
| `Excluded _, `Excluded _ -> top_of IInt
394+
| `Excluded _, `Excluded _ -> None
396395
(* Is x equal to an exclusion set, if it is a member then NO otherwise we
397396
* don't know: *)
398-
| `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt false else top_of IInt
399-
| `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt false else top_of IInt
397+
| `Definite x, `Excluded (s,r) -> if S.mem x s then Some false else None
398+
| `Excluded (s,r), `Definite x -> if S.mem x s then Some false else None
400399
(* The good case: *)
401-
| `Definite x, `Definite y -> of_bool IInt (x = y)
402-
| `Bot, `Bot -> `Bot
400+
| `Definite x, `Definite y -> Some (x = y)
401+
| `Bot, `Bot -> None
403402
| _ ->
404403
(* If only one of them is bottom, we raise an exception that eval_rv will catch *)
405404
raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
406405

407406
(* The inequality check: *)
408407
let ne ik x y = match x,y with
409408
(* Not much to do with two exclusion sets: *)
410-
| `Excluded _, `Excluded _ -> top_of IInt
409+
| `Excluded _, `Excluded _ -> None
411410
(* Is x unequal to an exclusion set, if it is a member then Yes otherwise we
412411
* don't know: *)
413-
| `Definite x, `Excluded (s,r) -> if S.mem x s then of_bool IInt true else top_of IInt
414-
| `Excluded (s,r), `Definite x -> if S.mem x s then of_bool IInt true else top_of IInt
412+
| `Definite x, `Excluded (s,r) -> if S.mem x s then Some true else None
413+
| `Excluded (s,r), `Definite x -> if S.mem x s then Some true else None
415414
(* The good case: *)
416-
| `Definite x, `Definite y -> of_bool IInt (x <> y)
417-
| `Bot, `Bot -> `Bot
415+
| `Definite x, `Definite y -> Some (x <> y)
416+
| `Bot, `Bot -> None
418417
| _ ->
419418
(* If only one of them is bottom, we raise an exception that eval_rv will catch *)
420419
raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
@@ -436,26 +435,26 @@ struct
436435

437436
(* Comparison handling copied from Enums. *)
438437
let handle_bot x y f = match x, y with
439-
| `Bot, `Bot -> `Bot
438+
| `Bot, `Bot -> None
440439
| `Bot, _
441440
| _, `Bot -> raise (ArithmeticOnIntegerBot (Printf.sprintf "%s op %s" (show x) (show y)))
442441
| _, _ -> f ()
443442

444443
let lt ik x y =
445444
handle_bot x y (fun () ->
446445
match minimal x, maximal x, minimal y, maximal y with
447-
| _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> of_bool ik true
448-
| Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> of_bool ik false
449-
| _, _, _, _ -> top_bool)
446+
| _, Some x2, Some y1, _ when Z.compare x2 y1 < 0 -> Some true
447+
| Some x1, _, _, Some y2 when Z.compare x1 y2 >= 0 -> Some false
448+
| _, _, _, _ -> None)
450449

451450
let gt ik x y = lt ik y x
452451

453452
let le ik x y =
454453
handle_bot x y (fun () ->
455454
match minimal x, maximal x, minimal y, maximal y with
456-
| _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> of_bool ik true
457-
| Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> of_bool ik false
458-
| _, _, _, _ -> top_bool)
455+
| _, Some x2, Some y1, _ when Z.compare x2 y1 <= 0 -> Some true
456+
| Some x1, _, _, Some y2 when Z.compare x1 y2 > 0 -> Some false
457+
| _, _, _, _ -> None)
459458

460459
let ge ik x y = le ik y x
461460

@@ -576,7 +575,7 @@ struct
576575
of_bool ik true
577576
| _, _ ->
578577
lift2 IntOps.BigIntOps.c_logor ik x y
579-
let c_lognot ik = eq ik (of_int ik Z.zero)
578+
let c_lognot ik x = match eq ik (of_int ik Z.zero) x with None -> top_of IInt | Some x -> of_bool IInt x (* TODO: avoid conversion *)
580579

581580
let invariant_ikind e ik (x:t) =
582581
match x with

0 commit comments

Comments
 (0)