Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize and refactor "Hoare" domains #809

Merged
merged 81 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
768b4fb
Add tests to show buggy Hoare domain usage
sim642 Jul 29, 2022
ec013be
Attempt to reimplement AddressDomain using projective hoare domain
sim642 Jul 29, 2022
7ad1c08
Attempt to reimplement AddressDomain using pairwise hoare domain
sim642 Jul 29, 2022
bda314f
Fix projective AddressDomain by wrapping pairwise
sim642 Jul 29, 2022
1925e6c
Use more precise AddressDomain projection
sim642 Jul 29, 2022
1896076
Add example for old hash-based AddressDomain projection
sim642 Jul 29, 2022
82fb030
Deprecate HoareDomain.HoarePO
sim642 Aug 1, 2022
61690ed
Add joined set abstraction
sim642 Aug 1, 2022
ca0f3d8
Attempt to use Hoare domain for AddressDomain buckets
sim642 Aug 1, 2022
a0555e7
Fix HoareDomain.Pairwise narrow
sim642 Aug 1, 2022
c5f6698
Fix ValueDomain.widen calling AddressDomain.widen incorrectly
sim642 Aug 1, 2022
74fafef
Revert to projective AddressDomain
sim642 Aug 1, 2022
58dd22a
Use HoareDomain.Pairwise for PathSensitive2
sim642 Aug 1, 2022
ff03d1c
Fix Lval.Offset joinability transitivity
sim642 Aug 1, 2022
288c1ea
Add asserts about s1_match cardinality in HoareDomain.Pairwise
sim642 Aug 1, 2022
9f9ccbd
Remove is_element from HoareDomains
sim642 Aug 1, 2022
7438b26
Optimize and refactor HoareDomain.Projective
sim642 Aug 1, 2022
cd50cd9
Optimize and refactor HoareDomain.Pairwise
sim642 Aug 1, 2022
e2b3048
Replace module E with type elt in HoareDomain.NewS
sim642 Aug 1, 2022
14cfb4d
Rename should_join -> cong in HoareDomain
sim642 Aug 1, 2022
fd93942
Make HoareDomain.Pairwise asserts exact
sim642 Aug 1, 2022
6bc127e
Update LvalTest
sim642 Aug 2, 2022
da9c786
Extract SensitiveDomains
sim642 Aug 2, 2022
41e39fb
Move HoareDomain.Joined -> SetDomain.Joined
sim642 Aug 2, 2022
1113247
Remove SensitiveDomain.NewS
sim642 Aug 2, 2022
77792bd
Rename SensitiveDomain.Equivalence -> Congruence
sim642 Aug 2, 2022
1e006d6
Add SensitiveDomain.Combined
sim642 Aug 2, 2022
b792000
Weaken SensitiveDomain E argument signatures
sim642 Aug 2, 2022
6f88615
Fix MapDomainTest
sim642 Aug 2, 2022
fed13ae
Rename Q -> C in Sensitive.Pairwise
sim642 Aug 2, 2022
868519f
Implement missing SetDomain.Joined operations
sim642 Aug 2, 2022
3db120e
Handle Lattice.BotValue in SensitiveDomain
sim642 Aug 2, 2022
d77e476
Make SensitiveDomain.Congruence over elt not t in Combined
sim642 Aug 2, 2022
d012f03
Clean up AddressDomain construction
sim642 Aug 2, 2022
8d6b8cf
Clean up PathSensitive2 construction
sim642 Aug 2, 2022
fdcb8c4
Add assert to 00-sanity/34-hoare-over-addrs
sim642 Aug 3, 2022
32f8567
Merge branch 'hoare-use-bugs' into hoaredomain-new
sim642 Aug 3, 2022
51c8c01
Expand descriptions of hoare-over tests
sim642 Aug 3, 2022
5f4d3e1
Merge branch 'master' into hoaredomain-new
sim642 Aug 3, 2022
5625a63
Switch AddressDomain back to Joined for StrPtr compatibility
sim642 Aug 3, 2022
e3bbd31
Implement Map versions of SensitiveDomain for WitnessConstraints
sim642 Aug 4, 2022
ae50c20
Use PairwiseMap for PathSensitive.Sync
sim642 Aug 4, 2022
d04cd22
Add physical equality short-circuiting to AddressDomain
sim642 Aug 5, 2022
b261e20
Add value output to PairwiseMap
sim642 Aug 5, 2022
bc1527f
Use normal sets for WitnessConstraints ranges
sim642 Aug 5, 2022
24a2fd1
Remove commented out sensitive map code
sim642 Aug 5, 2022
421cf57
Use MapDomain.S for PairwiseMap
sim642 Aug 5, 2022
13ec33e
Add Set suffix to SensitiveDomain sets
sim642 Aug 5, 2022
e39c3fc
Reuse Set and Map printing for SensitiveDomain
sim642 Aug 5, 2022
8a7b601
Implement pretty_diff for SensitiveDomains
sim642 Aug 5, 2022
9ded167
Remove Node and Edge modules from WitnessConstraints
sim642 Aug 5, 2022
47d2bec
Merge branch 'hoaredomain-new-map' into hoaredomain-new
sim642 Aug 5, 2022
7e109cc
Deprecate HoareDomain.MapBot and SetDomain.SensitiveConf
sim642 Aug 5, 2022
4782ccd
Document sensitive domains and related
sim642 Aug 5, 2022
3c35b20
Debug PathSensitive3 sync Not_found crash
sim642 Aug 8, 2022
e5799bc
Work around old LibraryFunctions spawning even with sem.unknown_funct…
sim642 Aug 8, 2022
dd0c0fe
Fix GraphML witnesses with threadspawn
sim642 Aug 8, 2022
1afc8f3
Add witness lifter fixpoint not reached test from sv-benchmarks
sim642 Aug 8, 2022
cde436f
Fix fixpoint not reached error in sv-benchmarks
sim642 Aug 8, 2022
5cb2778
Merge branch 'master' into hoaredomain-new
sim642 Aug 10, 2022
4d4c045
Revert "Fix Lval.Offset joinability transitivity"
sim642 Aug 11, 2022
881ad37
Remove index 0 and first field handling attempt from AddressDomain bu…
sim642 Aug 11, 2022
224a4b6
Remove PairwiseSet from AddressDomain
sim642 Aug 11, 2022
bd0bc27
Remove unused trace_enabled from MapDomain.PMap
sim642 Aug 11, 2022
a0a375a
Revert "Update LvalTest"
sim642 Aug 11, 2022
8d78694
Merge branch 'hoaredomain-new-ad-proj' into hoaredomain-new
sim642 Aug 11, 2022
c19a345
Document Lval special cases not used by AddressDomain splitting any more
sim642 Aug 11, 2022
4e2057e
Rename SensitiveDomain -> DisjointDomain
sim642 Aug 11, 2022
3a2a226
Add witness lifter path sensitive unsound branch test
sim642 Aug 22, 2022
9e52524
Fix witness lifter mishandling Deadcode exceptions
sim642 Aug 22, 2022
256fa17
Move commented-out add code in MapDomain
sim642 Aug 24, 2022
236c76e
Improve HoareDomain and DisjointDomain documentation
sim642 Aug 24, 2022
b16700a
Rename HoareDomain.Set2 -> SetEM
sim642 Aug 24, 2022
2946dcd
Move and document Lval bucket representatives
sim642 Aug 24, 2022
a2d0cea
Use SetDomain.Print for AddressDomain
sim642 Aug 24, 2022
901a709
Fix comment typo in AddressDomain
sim642 Sep 2, 2022
41bfdba
Document SetDomain strong removal
sim642 Sep 2, 2022
f630ebf
Document abstract SetDomain element-wise operations
sim642 Sep 2, 2022
c975d09
Use physical equality short-circuit for AddressDomain.leq
sim642 Sep 2, 2022
cafb5fa
Merge branch 'master' into hoaredomain-new
sim642 Sep 2, 2022
af734d8
Add address domain first field and zero index tests
sim642 Sep 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/analyses/base.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2446,7 +2446,11 @@ struct
in
List.filter_map (create_thread (Some (Mem id, NoOffset)) (Some ptc_arg)) start_funvars_with_unknown
end
| _, _ ->
| _, _ when get_bool "sem.unknown_function.spawn" ->
(* TODO: Remove sem.unknown_function.spawn check because it is (and should be) really done in LibraryFunctions.
But here we consider all non-ThreadCrate functions also unknown, so old-style LibraryFunctions access
definitions using `Write would still spawn because they are not truly unknown functions (missing from LibraryFunctions).
Need this to not have memmove spawn in SV-COMP. *)
let shallow_args = LibraryDesc.Accesses.find desc.accs { kind = Spawn; deep = false } args in
let deep_args = LibraryDesc.Accesses.find desc.accs { kind = Spawn; deep = true } args in
let shallow_flist = collect_invalidate ~deep:false (Analyses.ask_of_ctx ctx) ctx.global ctx.local shallow_args in
Expand All @@ -2455,6 +2459,7 @@ struct
let addrs = List.concat_map AD.to_var_may flist in
if addrs <> [] then M.debug ~category:Analyzer "Spawning functions from unknown function: %a" (d_list ", " d_varinfo) addrs;
List.filter_map (create_thread None None) addrs
| _, _ -> []

let assert_fn ctx e refine =
(* make the state meet the assertion in the rest of the code *)
Expand Down
79 changes: 52 additions & 27 deletions src/cdomains/addressDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,32 @@ end

module AddressSet (Idx: IntDomain.Z) =
struct
include Printable.Std (* for default invariant, tag, ... *)
module Addr = Lval.NormalLatRepr (Idx)
module J = SetDomain.Joined (Addr)
(* module H = HoareDomain.SetEM (Addr) *)
(* Hoare set for bucket doesn't play well with StrPtr limiting:
https://github.com/goblint/analyzer/pull/808 *)
include DisjointDomain.ProjectiveSet (Addr) (J) (Addr.R)

module Addr = Lval.NormalLat (Idx)
include HoareDomain.HoarePO (Addr)
(* short-circuit with physical equality,
makes a difference at long-scale: https://github.com/goblint/analyzer/pull/809#issuecomment-1206174751 *)
let equal x y = x == y || equal x y

let widen x y =
if M.tracing then M.traceli "ad" "widen %a %a\n" pretty x pretty y;
let r = widen x y in
if M.tracing then M.traceu "ad" "-> %a\n" pretty r;
r
let join x y =
if M.tracing then M.traceli "ad" "join %a %a\n" pretty x pretty y;
let r = join x y in
if M.tracing then M.traceu "ad" "-> %a\n" pretty r;
r
let leq x y =
if M.tracing then M.traceli "ad" "leq %a %a\n" pretty x pretty y;
let r = x == y || leq x y in (* short-circuit with physical equality, not benchmarked *)
if M.tracing then M.traceu "ad" "-> %B\n" r;
r

type field = Addr.field
type idx = Idx.t
Expand All @@ -41,6 +57,7 @@ struct
let not_null = unknown_ptr
let top_ptr = of_list Addr.([UnknownPtr; NullPtr])
let may_be_unknown x = exists (fun e -> e = Addr.UnknownPtr) x
let is_element a x = cardinal x = 1 && Addr.equal (choose x) a
let is_null x = is_element Addr.NullPtr x
let is_not_null x = for_all (fun e -> e <> Addr.NullPtr) x
let may_be_null x = exists (fun e -> e = Addr.NullPtr) x
Expand Down Expand Up @@ -83,30 +100,26 @@ struct
let to_string x = List.filter_map Addr.to_string (elements x)

(* add an & in front of real addresses *)
let short_addr a =
match Addr.to_var a with
| Some _ -> "&" ^ Addr.show a
| None -> Addr.show a

let pretty () x =
try
let content = List.map (fun a -> text (short_addr a)) (elements x) in
let rec separate x =
match x with
| [] -> []
| [x] -> [x]
| (x::xs) -> x ++ (text ", ") :: separate xs
in
let separated = separate content in
let content = List.fold_left (++) nil separated in
(text "{") ++ content ++ (text "}")
with SetDomain.Unsupported _ -> pretty () x

let show x : string =
try
let all_elems : string list = List.map short_addr (elements x) in
Printable.get_short_list "{" "}" all_elems
with SetDomain.Unsupported _ -> show x
module ShortAddr =
struct
include Addr

let show a =
match Addr.to_var a with
| Some _ -> "&" ^ Addr.show a
| None -> Addr.show a

let pretty () a = Pretty.text (show a)
end

include SetDomain.Print (ShortAddr) (
struct
type nonrec t = t
type nonrec elt = elt
let elements = elements
let iter = iter
end
)

(*
let leq = if not fast_addr_sets then leq else fun x y ->
Expand Down Expand Up @@ -140,4 +153,16 @@ struct

let meet x y = merge join meet x y
let narrow x y = merge (fun x y -> widen x (join x y)) narrow x y

let meet x y =
if M.tracing then M.traceli "ad" "meet %a %a\n" pretty x pretty y;
let r = meet x y in
if M.tracing then M.traceu "ad" "-> %a\n" pretty r;
r

let narrow x y =
if M.tracing then M.traceli "ad" "narrow %a %a\n" pretty x pretty y;
let r = narrow x y in
if M.tracing then M.traceu "ad" "-> %a\n" pretty r;
r
end
56 changes: 47 additions & 9 deletions src/cdomains/lval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct
match x, y with
| `NoOffset , `NoOffset -> true
| `NoOffset, x
| x, `NoOffset -> cmp_zero_offset x = `MustZero (* cannot derive due to this special case *)
| x, `NoOffset -> cmp_zero_offset x = `MustZero (* cannot derive due to this special case, special cases not used for AddressDomain any more due to splitting *)
michael-schwarz marked this conversation as resolved.
Show resolved Hide resolved
| `Field (f1,o1), `Field (f2,o2) when CilType.Fieldinfo.equal f1 f2 -> equal o1 o2
| `Index (i1,o1), `Index (i2,o2) when Idx.equal i1 i2 -> equal o1 o2
| _ -> false
Expand All @@ -61,7 +61,7 @@ struct
let pretty_diff () (x,y) =
dprintf "%s: %a not leq %a" (name ()) pretty x pretty y

let rec hash = function
let rec hash = function (* special cases not used for AddressDomain any more due to splitting *)
| `NoOffset -> 1
| `Field (f,o) when not (is_first_field f) -> Hashtbl.hash f.fname * hash o + 13
| `Field (_,o) (* zero offsets need to yield the same hash as `NoOffset! *)
Expand All @@ -86,7 +86,7 @@ struct
let rec compare o1 o2 = match o1, o2 with
| `NoOffset, `NoOffset -> 0
| `NoOffset, x
| x, `NoOffset when cmp_zero_offset x = `MustZero -> 0 (* cannot derive due to this special case *)
| x, `NoOffset when cmp_zero_offset x = `MustZero -> 0 (* cannot derive due to this special case, special cases not used for AddressDomain any more due to splitting *)
| `Field (f1,o1), `Field (f2,o2) ->
let c = CilType.Fieldinfo.compare f1 f2 in
if c=0 then compare o1 o2 else c
Expand All @@ -112,8 +112,8 @@ struct
let rec leq x y =
match x, y with
| `NoOffset, `NoOffset -> true
| `NoOffset, x -> cmp_zero_offset x <> `MustNonzero
| x, `NoOffset -> cmp_zero_offset x = `MustZero
| `NoOffset, x -> cmp_zero_offset x <> `MustNonzero (* special case not used for AddressDomain any more due to splitting *)
| x, `NoOffset -> cmp_zero_offset x = `MustZero (* special case not used for AddressDomain any more due to splitting *)
| `Index (i1,o1), `Index (i2,o2) when Idx.leq i1 i2 -> leq o1 o2
| `Field (f1,o1), `Field (f2,o2) when CilType.Fieldinfo.equal f1 f2 -> leq o1 o2
| _ -> false
Expand All @@ -123,13 +123,13 @@ struct
match x, y with
| `NoOffset, `NoOffset -> `NoOffset
| `NoOffset, x
| x, `NoOffset -> (match cop, cmp_zero_offset x with
| x, `NoOffset -> (match cop, cmp_zero_offset x with (* special cases not used for AddressDomain any more due to splitting *)
| (`Join | `Widen), (`MustZero | `MayZero) -> x
| (`Meet | `Narrow), (`MustZero | `MayZero) -> `NoOffset
| _ -> raise Lattice.Uncomparable)
| `Field (x1,y1), `Field (x2,y2) when CilType.Fieldinfo.equal x1 x2 -> `Field (x1, merge cop y1 y2)
| `Index (x1,y1), `Index (x2,y2) -> `Index (op x1 x2, merge cop y1 y2)
| _ -> raise Lattice.Uncomparable
| _ -> raise Lattice.Uncomparable (* special case not used for AddressDomain any more due to splitting *)

let join x y = merge `Join x y
let meet x y = merge `Meet x y
Expand Down Expand Up @@ -178,7 +178,7 @@ struct
type field = fieldinfo
type idx = Idx.t
module Offs = OffsetPrintable (Idx)

type t =
| Addr of CilType.Varinfo.t * Offs.t (** Pointer to offset of a variable. *)
| NullPtr (** NULL pointer. *)
Expand Down Expand Up @@ -309,6 +309,15 @@ struct
let arbitrary () = QCheck.always UnknownPtr (* S TODO: non-unknown *)
end

(** Lvalue lattice.

Actually a disjoint union of lattices without top or bottom.
Lvalues are grouped as follows:

- Each {!Addr}, modulo precise index expressions in offset, is a sublattice with ordering induced by {!Offset}.
- {!NullPtr} is a singleton sublattice.
- {!UnknownPtr} is a singleton sublattice.
- If [ana.base.limit-string-addresses] is enabled, then all {!StrPtr} are together in one sublattice with flat ordering. If [ana.base.limit-string-addresses] is disabled, then each {!StrPtr} is a singleton sublattice. *)
module NormalLat (Idx: IntDomain.Z) =
struct
include Normal (Idx)
Expand Down Expand Up @@ -343,7 +352,11 @@ struct
| None, a
| a, None -> a
| Some a, Some b when a = b -> Some a
| Some a, Some b (* when a <> b *) -> raise Lattice.Uncomparable
| Some a, Some b (* when a <> b *) ->
if GobConfig.get_bool "ana.base.limit-string-addresses" then
raise Lattice.BotValue
else
raise Lattice.Uncomparable

let merge cop x y =
match x, y with
Expand All @@ -363,9 +376,34 @@ struct
let meet = merge `Meet
let narrow = merge `Narrow

include Lattice.NoBotTop

let pretty_diff () (x,y) = dprintf "%s: %a not leq %a" (name ()) pretty x pretty y
end

(** Lvalue lattice with sublattice representatives for {!DisjointDomain}. *)
module NormalLatRepr (Idx: IntDomain.Z) =
struct
include NormalLat (Idx)

(** Representatives for lvalue sublattices as defined by {!NormalLat}. *)
module R: DisjointDomain.Representative with type elt = t =
struct
include Normal (Idx)
type elt = t

let rec of_elt_offset: Offs.t -> Offs.t =
function
| `NoOffset -> `NoOffset
| `Field (f,o) -> `Field (f, of_elt_offset o)
| `Index (_,o) -> `Index (Idx.top (), of_elt_offset o) (* all indices to same bucket *)
let of_elt = function
| Addr (v, o) -> Addr (v, of_elt_offset o) (* addrs grouped by var and part of offset *)
| StrPtr _ when GobConfig.get_bool "ana.base.limit-string-addresses" -> StrPtr None (* all strings together if limited *)
| a -> a (* everything else is kept separate, including strings if not limited *)
end
end

module Fields =
struct
module F = CilType.Fieldinfo
Expand Down
14 changes: 8 additions & 6 deletions src/cdomains/valueDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -562,11 +562,12 @@ struct
| (x, `Bot) -> x
| (`Int x, `Int y) -> (try `Int (ID.widen x y) with IntDomain.IncompatibleIKinds m -> Messages.warn ~category:Analyzer "%s" m; `Top)
| (`Float x, `Float y) -> `Float (FD.widen x y)
(* TODO: symmetric widen, wtf? *)
| (`Int x, `Address y)
| (`Address y, `Int x) -> `Address (match ID.to_int x with
jerhard marked this conversation as resolved.
Show resolved Hide resolved
| Some x when BI.equal BI.zero x -> AD.widen AD.null_ptr y
| Some x -> AD.(widen y not_null)
| None -> AD.widen y AD.top_ptr)
| Some x when BI.equal BI.zero x -> AD.widen AD.null_ptr (AD.join AD.null_ptr y)
| Some x -> AD.(widen y (join y not_null))
| None -> AD.widen y (AD.join y AD.top_ptr))
michael-schwarz marked this conversation as resolved.
Show resolved Hide resolved
| (`Address x, `Address y) -> `Address (AD.widen x y)
| (`Struct x, `Struct y) -> `Struct (Structs.widen_with_fct widen_elem x y)
| (`Union (f,x), `Union (g,y)) -> `Union (match UnionDomain.Field.widen f g with
Expand Down Expand Up @@ -647,11 +648,12 @@ struct
| (x, `Bot) -> x
| (`Int x, `Int y) -> (try `Int (ID.widen x y) with IntDomain.IncompatibleIKinds m -> Messages.warn ~category:Analyzer "%s" m; `Top)
| (`Float x, `Float y) -> `Float (FD.widen x y)
(* TODO: symmetric widen, wtf? *)
| (`Int x, `Address y)
| (`Address y, `Int x) -> `Address (match ID.to_int x with
| Some x when BI.equal x BI.zero -> AD.widen AD.null_ptr y
| Some x -> AD.(widen y not_null)
| None -> AD.widen y AD.top_ptr)
| Some x when BI.equal x BI.zero -> AD.widen AD.null_ptr (AD.join AD.null_ptr y)
| Some x -> AD.(widen y (join y not_null))
| None -> AD.widen y (AD.join y AD.top_ptr))
michael-schwarz marked this conversation as resolved.
Show resolved Hide resolved
| (`Address x, `Address y) -> `Address (AD.widen x y)
| (`Struct x, `Struct y) -> `Struct (Structs.widen x y)
| (`Union (f,x), `Union (g,y)) -> `Union (match UnionDomain.Field.widen f g with
Expand Down