Skip to content

Commit 641d447

Browse files
committed
Merge branch 'master' into yaml-witness-ghost
2 parents 58aaf53 + b9caf63 commit 641d447

40 files changed

+1012
-304
lines changed

dune-project

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ Goblint includes analyses for assertions, overflows, deadlocks, etc and can be e
4545
(ppx_deriving (>= 6.0.2))
4646
(ppx_deriving_hash (>= 0.1.2))
4747
(ppx_deriving_yojson (>= 3.7.0))
48+
(ppxlib (>= 0.30.0)) ; ppx_easy_deriving
4849
(ounit2 :with-test)
4950
(qcheck-ounit :with-test)
5051
(odoc :with-doc)

goblint.opam

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ depends: [
4545
"ppx_deriving" {>= "6.0.2"}
4646
"ppx_deriving_hash" {>= "0.1.2"}
4747
"ppx_deriving_yojson" {>= "3.7.0"}
48+
"ppxlib" {>= "0.30.0"}
4849
"ounit2" {with-test}
4950
"qcheck-ounit" {with-test}
5051
"odoc" {with-doc}

scripts/goblint-lib-modules.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@
4242
"Goblint_build_info",
4343
"Dune_build_info",
4444

45+
# ppx-s
46+
"Ppx_deriving_printable",
47+
"Ppx_deriving_lattice",
48+
4549
"MessageCategory", # included in Messages
4650
"PreValueDomain", # included in ValueDomain
4751
"WitnessGhostVar", # included in WitnessGhost

src/cdomain/value/cdomains/floatDomain.ml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,7 +1134,7 @@ module FloatDomTupleImpl = struct
11341134
module F1 = FloatIntervalImplLifted
11351135
open Batteries
11361136

1137-
type t = F1.t option [@@deriving to_yojson, eq, ord]
1137+
type t = F1.t option [@@deriving eq, ord, hash]
11381138

11391139
let name () = "floatdomtuple"
11401140

@@ -1181,10 +1181,6 @@ module FloatDomTupleImpl = struct
11811181
Option.map_default identity ""
11821182
(mapp { fp= (fun (type a) (module F : FloatDomain with type t = a) x -> F.name () ^ ":" ^ F.show x); } x)
11831183

1184-
let hash x =
1185-
Option.map_default identity 0
1186-
(mapp { fp= (fun (type a) (module F : FloatDomain with type t = a) -> F.hash); } x)
1187-
11881184
let of_const fkind =
11891185
create { fi= (fun (type a) (module F : FloatDomain with type t = a) -> F.of_const fkind); }
11901186

src/cdomain/value/cdomains/intDomain.ml

Lines changed: 108 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,59 @@ module IntervalArith (Ints_t : IntOps.IntOps) = struct
582582
List.exists (Z.equal l) ts
583583
end
584584

585+
module IntInvariant =
586+
struct
587+
let of_int e ik x =
588+
if get_bool "witness.invariant.exact" then
589+
Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType))
590+
else
591+
Invariant.none
592+
593+
let of_incl_list e ik ps =
594+
match ps with
595+
| [_; _] when ik = IBool && not (get_bool "witness.invariant.inexact-type-bounds") ->
596+
assert (List.mem Z.zero ps);
597+
assert (List.mem Z.one ps);
598+
Invariant.none
599+
| [_] when get_bool "witness.invariant.exact" ->
600+
Invariant.none
601+
| _ :: _ :: _
602+
| [_] | [] ->
603+
List.fold_left (fun a x ->
604+
let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in
605+
Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *)
606+
) (Invariant.bot ()) ps
607+
608+
let of_interval_opt e ik = function
609+
| (Some x1, Some x2) when Z.equal x1 x2 ->
610+
of_int e ik x1
611+
| x1_opt, x2_opt ->
612+
let (min_ik, max_ik) = Size.range ik in
613+
let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in
614+
let i1 =
615+
match x1_opt, inexact_type_bounds with
616+
| Some x1, false when Z.equal min_ik x1 -> Invariant.none
617+
| Some x1, _ -> Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1, e, intType))
618+
| None, _ -> Invariant.none
619+
in
620+
let i2 =
621+
match x2_opt, inexact_type_bounds with
622+
| Some x2, false when Z.equal x2 max_ik -> Invariant.none
623+
| Some x2, _ -> Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2, intType))
624+
| None, _ -> Invariant.none
625+
in
626+
Invariant.(i1 && i2)
627+
628+
let of_interval e ik (x1, x2) =
629+
of_interval_opt e ik (Some x1, Some x2)
630+
631+
let of_excl_list e ik ns =
632+
List.fold_left (fun a x ->
633+
let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in
634+
Invariant.(a && i)
635+
) (Invariant.top ()) ns
636+
end
637+
585638
module IntervalFunctor (Ints_t : IntOps.IntOps): SOverflow with type int_t = Ints_t.t and type t = (Ints_t.t * Ints_t.t) option =
586639
struct
587640
let name () = "intervals"
@@ -915,21 +968,10 @@ struct
915968
else if Ints_t.compare y2 x1 <= 0 then of_bool ik false
916969
else top_bool
917970

918-
let invariant_ikind e ik x =
919-
match x with
920-
| Some (x1, x2) when Ints_t.compare x1 x2 = 0 ->
921-
if get_bool "witness.invariant.exact" then
922-
let x1 = Ints_t.to_bigint x1 in
923-
Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x1, intType))
924-
else
925-
Invariant.top ()
971+
let invariant_ikind e ik = function
926972
| Some (x1, x2) ->
927-
let (min_ik, max_ik) = range ik in
928-
let (x1', x2') = BatTuple.Tuple2.mapn (Ints_t.to_bigint) (x1, x2) in
929-
let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in
930-
let i1 = if inexact_type_bounds || Ints_t.compare min_ik x1 <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik x1', e, intType)) else Invariant.none in
931-
let i2 = if inexact_type_bounds || Ints_t.compare x2 max_ik <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik x2', intType)) else Invariant.none in
932-
Invariant.(i1 && i2)
973+
let (x1', x2') = BatTuple.Tuple2.mapn Ints_t.to_bigint (x1, x2) in
974+
IntInvariant.of_interval e ik (x1', x2')
933975
| None -> Invariant.none
934976

935977
let arbitrary ik =
@@ -2297,25 +2339,14 @@ struct
22972339
let invariant_ikind e ik (x:t) =
22982340
match x with
22992341
| `Definite x ->
2300-
if get_bool "witness.invariant.exact" then
2301-
Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType))
2302-
else
2303-
Invariant.top ()
2342+
IntInvariant.of_int e ik x
23042343
| `Excluded (s, r) ->
23052344
(* Emit range invariant if tighter than ikind bounds.
23062345
This can be more precise than interval, which has been widened. *)
23072346
let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in
2308-
let (ikmin, ikmax) =
2309-
let ikr = size ik in
2310-
(Exclusion.min_of_range ikr, Exclusion.max_of_range ikr)
2311-
in
2312-
let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in
2313-
let imin = if inexact_type_bounds || Z.compare ikmin rmin <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik rmin, e, intType)) else Invariant.none in
2314-
let imax = if inexact_type_bounds || Z.compare rmax ikmax <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik rmax, intType)) else Invariant.none in
2315-
S.fold (fun x a ->
2316-
let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in
2317-
Invariant.(a && i)
2318-
) s Invariant.(imin && imax)
2347+
let ri = IntInvariant.of_interval e ik (rmin, rmax) in
2348+
let si = IntInvariant.of_excl_list e ik (S.elements s) in
2349+
Invariant.(ri && si)
23192350
| `Bot -> Invariant.none
23202351

23212352
let arbitrary ik =
@@ -2731,32 +2762,16 @@ module Enums : S with type int_t = Z.t = struct
27312762
let ne ik x y = c_lognot ik (eq ik x y)
27322763

27332764
let invariant_ikind e ik x =
2734-
let inexact_type_bounds = get_bool "witness.invariant.inexact-type-bounds" in
27352765
match x with
2736-
| Inc ps when not inexact_type_bounds && ik = IBool && is_top_of ik x ->
2737-
Invariant.none
27382766
| Inc ps ->
2739-
if BISet.cardinal ps > 1 || get_bool "witness.invariant.exact" then
2740-
BISet.fold (fun x a ->
2741-
let i = Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik x, intType)) in
2742-
Invariant.(a || i) [@coverage off] (* bisect_ppx cannot handle redefined (||) *)
2743-
) ps (Invariant.bot ())
2744-
else
2745-
Invariant.top ()
2767+
IntInvariant.of_incl_list e ik (BISet.elements ps)
27462768
| Exc (ns, r) ->
27472769
(* Emit range invariant if tighter than ikind bounds.
27482770
This can be more precise than interval, which has been widened. *)
27492771
let (rmin, rmax) = (Exclusion.min_of_range r, Exclusion.max_of_range r) in
2750-
let (ikmin, ikmax) =
2751-
let ikr = size ik in
2752-
(Exclusion.min_of_range ikr, Exclusion.max_of_range ikr)
2753-
in
2754-
let imin = if inexact_type_bounds || Z.compare ikmin rmin <> 0 then Invariant.of_exp Cil.(BinOp (Le, kintegerCilint ik rmin, e, intType)) else Invariant.none in
2755-
let imax = if inexact_type_bounds || Z.compare rmax ikmax <> 0 then Invariant.of_exp Cil.(BinOp (Le, e, kintegerCilint ik rmax, intType)) else Invariant.none in
2756-
BISet.fold (fun x a ->
2757-
let i = Invariant.of_exp Cil.(BinOp (Ne, e, kintegerCilint ik x, intType)) in
2758-
Invariant.(a && i)
2759-
) ns Invariant.(imin && imax)
2772+
let ri = IntInvariant.of_interval e ik (rmin, rmax) in
2773+
let nsi = IntInvariant.of_excl_list e ik (BISet.elements ns) in
2774+
Invariant.(ri && nsi)
27602775

27612776

27622777
let arbitrary ik =
@@ -2779,7 +2794,7 @@ module Enums : S with type int_t = Z.t = struct
27792794
| Inc e, Some (c, m) -> Inc (BISet.filter (contains c m) e)
27802795
| _ -> a
27812796

2782-
let refine_with_interval ik a b = a
2797+
let refine_with_interval ik a b = a (* TODO: refine inclusion (exclusion?) set *)
27832798

27842799
let refine_with_excl_list ik a b =
27852800
match b with
@@ -3243,10 +3258,7 @@ struct
32433258
match x with
32443259
| x when is_top x -> Invariant.top ()
32453260
| Some (c, m) when m =: Z.zero ->
3246-
if get_bool "witness.invariant.exact" then
3247-
Invariant.of_exp Cil.(BinOp (Eq, e, Cil.kintegerCilint ik c, intType))
3248-
else
3249-
Invariant.top ()
3261+
IntInvariant.of_int e ik c
32503262
| Some (c, m) ->
32513263
let open Cil in
32523264
let (c, m) = BatTuple.Tuple2.mapn (fun a -> kintegerCilint ik a) (c, m) in
@@ -3338,7 +3350,7 @@ module IntDomTupleImpl = struct
33383350
module I5 = IntervalSetFunctor (IntOps.BigIntOps)
33393351

33403352
type t = I1.t option * I2.t option * I3.t option * I4.t option * I5.t option
3341-
[@@deriving to_yojson, eq, ord]
3353+
[@@deriving eq, ord, hash]
33423354

33433355
let name () = "intdomtuple"
33443356

@@ -3524,7 +3536,7 @@ module IntDomTupleImpl = struct
35243536
let merge ps =
35253537
let (vs, rs) = List.split ps in
35263538
let (mins, maxs) = List.split rs in
3527-
(List.concat vs, (List.min mins, List.max maxs))
3539+
(List.concat vs |> List.sort_uniq Z.compare, (List.min mins, List.max maxs))
35283540
in
35293541
mapp2 { fp2 = fun (type a) (module I:SOverflow with type t = a and type int_t = int_t) -> I.to_excl_list } x |> flat merge
35303542

@@ -3565,7 +3577,7 @@ module IntDomTupleImpl = struct
35653577
in
35663578
[(fun (a, b, c, d, e) -> refine_with_excl_list ik (a, b, c, d, e) (to_excl_list (a, b, c, d, e)));
35673579
(fun (a, b, c, d, e) -> refine_with_incl_list ik (a, b, c, d, e) (to_incl_list (a, b, c, d, e)));
3568-
(fun (a, b, c, d, e) -> maybe refine_with_interval ik (a, b, c, d, e) b);
3580+
(fun (a, b, c, d, e) -> maybe refine_with_interval ik (a, b, c, d, e) b); (* TODO: get interval across all domains with minimal and maximal *)
35693581
(fun (a, b, c, d, e) -> maybe refine_with_congruence ik (a, b, c, d, e) d)]
35703582

35713583
let refine ik ((a, b, c, d, e) : t ) : t =
@@ -3665,7 +3677,6 @@ module IntDomTupleImpl = struct
36653677
|> to_list
36663678
|> String.concat "; "
36673679
let to_yojson = [%to_yojson: Yojson.Safe.t list] % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) x -> I.to_yojson x }
3668-
let hash = List.fold_left (lxor) 0 % to_list % mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.hash }
36693680

36703681
(* `map/opt_map` are used by `project` *)
36713682
let opt_map b f =
@@ -3778,19 +3789,47 @@ module IntDomTupleImpl = struct
37783789
| Some v when not (GobConfig.get_bool "dbg.full-output") -> BatPrintf.fprintf f "<value>\n<data>\n%s\n</data>\n</value>\n" (Z.to_string v)
37793790
| _ -> BatPrintf.fprintf f "<value>\n<data>\n%s\n</data>\n</value>\n" (show x)
37803791

3781-
let invariant_ikind e ik x =
3782-
match to_int x with
3783-
| Some v ->
3784-
if get_bool "witness.invariant.exact" then
3785-
(* If definite, output single equality instead of every subdomain repeating same equality *)
3786-
Invariant.of_exp Cil.(BinOp (Eq, e, kintegerCilint ik v, intType))
3787-
else
3788-
Invariant.top ()
3789-
| None ->
3790-
let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x)
3791-
in List.fold_left (fun a i ->
3792+
let invariant_ikind e ik ((_, _, _, x_cong, x_intset) as x) =
3793+
(* TODO: do refinement before to ensure incl_list being more precise than intervals, etc (https://github.com/goblint/analyzer/pull/1517#discussion_r1693998515), requires refine functions to actually refine that *)
3794+
let simplify_int fallback =
3795+
match to_int x with
3796+
| Some v ->
3797+
(* If definite, output single equality instead of every subdomain repeating same equality (or something less precise). *)
3798+
IntInvariant.of_int e ik v
3799+
| None ->
3800+
fallback ()
3801+
in
3802+
let simplify_all () =
3803+
match to_incl_list x with
3804+
| Some ps ->
3805+
(* If inclusion set, output disjunction of equalities because it subsumes interval(s), exclusion set and congruence. *)
3806+
IntInvariant.of_incl_list e ik ps
3807+
| None ->
3808+
(* Get interval bounds from all domains (intervals and exclusion set ranges). *)
3809+
let min = minimal x in
3810+
let max = maximal x in
3811+
let ns = Option.map fst (to_excl_list x) |? [] in (* Ignore exclusion set bit range, known via interval bounds already. *)
3812+
(* "Refine" out-of-bounds exclusions for simpler output. *)
3813+
let ns = Option.map_default (fun min -> List.filter (Z.leq min) ns) ns min in
3814+
let ns = Option.map_default (fun max -> List.filter (Z.geq max) ns) ns max in
3815+
Invariant.(
3816+
IntInvariant.of_interval_opt e ik (min, max) && (* Output best interval bounds once instead of multiple subdomains repeating them (or less precise ones). *)
3817+
IntInvariant.of_excl_list e ik ns &&
3818+
Option.map_default (I4.invariant_ikind e ik) Invariant.none x_cong && (* Output congruence as is. *)
3819+
Option.map_default (I5.invariant_ikind e ik) Invariant.none x_intset (* Output interval sets as is. *)
3820+
)
3821+
in
3822+
let simplify_none () =
3823+
let is = to_list (mapp { fp = fun (type a) (module I:SOverflow with type t = a) -> I.invariant_ikind e ik } x) in
3824+
List.fold_left (fun a i ->
37923825
Invariant.(a && i)
37933826
) (Invariant.top ()) is
3827+
in
3828+
match GobConfig.get_string "ana.base.invariant.int.simplify" with
3829+
| "none" -> simplify_none ()
3830+
| "int" -> simplify_int simplify_none
3831+
| "all" -> simplify_int simplify_all
3832+
| _ -> assert false
37943833

37953834
let arbitrary ik = QCheck.(set_print show @@ tup5 (option (I1.arbitrary ik)) (option (I2.arbitrary ik)) (option (I3.arbitrary ik)) (option (I4.arbitrary ik)) (option (I5.arbitrary ik)))
37963835

src/cdomains/apron/relationDomain.apron.ml

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ end
146146
type ('a, 'b) relcomponents_t = {
147147
rel: 'a;
148148
priv: 'b;
149-
} [@@deriving eq, ord, hash, to_yojson]
149+
} [@@deriving eq, ord, hash, to_yojson, relift, lattice]
150150

151151
module RelComponents (D3: S3) (PrivD: Lattice.S):
152152
sig
@@ -155,13 +155,11 @@ sig
155155
end =
156156
struct
157157
module RD = D3
158-
type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson]
158+
type t = (RD.t, PrivD.t) relcomponents_t [@@deriving eq, ord, hash, to_yojson, relift, lattice]
159159

160160
include Printable.Std
161161
open Pretty
162162

163-
let relift {rel; priv} = {rel = RD.relift rel; priv = PrivD.relift priv}
164-
165163
let show r =
166164
let first = RD.show r.rel in
167165
let third = PrivD.show r.priv in
@@ -185,26 +183,11 @@ struct
185183
let tr = QCheck.pair (RD.arbitrary ()) (PrivD.arbitrary ()) in
186184
QCheck.map ~rev:to_tuple of_tuple tr
187185

188-
let bot () = {rel = RD.bot (); priv = PrivD.bot ()}
189-
let is_bot {rel; priv} = RD.is_bot rel && PrivD.is_bot priv
190-
let top () = {rel = RD.top (); priv = PrivD.bot ()}
191-
let is_top {rel; priv} = RD.is_top rel && PrivD.is_top priv
192-
193-
let leq {rel=x1; priv=x3 } {rel=y1; priv=y3} =
194-
RD.leq x1 y1 && PrivD.leq x3 y3
195-
196186
let pretty_diff () (({rel=x1; priv=x3}:t),({rel=y1; priv=y3}:t)): Pretty.doc =
197187
if not (RD.leq x1 y1) then
198188
RD.pretty_diff () (x1,y1)
199189
else
200190
PrivD.pretty_diff () (x3,y3)
201-
202-
let op_scheme op1 op3 {rel=x1; priv=x3} {rel=y1; priv=y3}: t =
203-
{rel = op1 x1 y1; priv = op3 x3 y3 }
204-
let join = op_scheme RD.join PrivD.join
205-
let meet = op_scheme RD.meet PrivD.meet
206-
let widen = op_scheme RD.widen PrivD.widen
207-
let narrow = op_scheme RD.narrow PrivD.narrow
208191
end
209192

210193

0 commit comments

Comments
 (0)