From 9ee9ce7ac842fdbc61fe9b6e6e158f7dff14c4cc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:31:46 +0200 Subject: [PATCH 001/103] Add reach_error to library functions --- src/util/library/libraryFunctions.ml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/util/library/libraryFunctions.ml b/src/util/library/libraryFunctions.ml index 53bf804b1d..92355ca89c 100644 --- a/src/util/library/libraryFunctions.ml +++ b/src/util/library/libraryFunctions.ml @@ -1029,6 +1029,7 @@ let svcomp_descs_list: (string * LibraryDesc.t) list = LibraryDsl.[ ("__VERIFIER_nondet_int", unknown []); (* declare invalidate actions to prevent invalidating globals when extern in regression tests *) ("__VERIFIER_nondet_size_t", unknown []); (* cannot give it in sv-comp.c without including stdlib or similar *) ("__VERIFIER_assert", special [__ "exp" []] @@ fun exp -> Assert { exp; check = true; refine = get_bool "sem.assert.refine" }); (* only used if definition missing (e.g. in evalAssert transformed output) or extraspecial *) + ("reach_error", special [] @@ Abort); (* only used if definition missing (e.g. in evalAssert transformed output) or extraspecial *) ] [@@coverage off] From 4752ddf320351654aa13e8beb831736d535a2280 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:32:03 +0200 Subject: [PATCH 002/103] Make some YAML witness validation messages more severe --- src/analyses/unassumeAnalysis.ml | 4 ++-- src/witness/yamlWitness.ml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/unassumeAnalysis.ml b/src/analyses/unassumeAnalysis.ml index 5895f242c9..9ec69727c0 100644 --- a/src/analyses/unassumeAnalysis.ml +++ b/src/analyses/unassumeAnalysis.ml @@ -252,13 +252,13 @@ struct | false, (LocationInvariant _ | LoopInvariant _ | PreconditionLoopInvariant _ | InvariantSet _) -> M.info_noloc ~category:Witness "disabled entry of type %s" target_type | _ -> - M.info_noloc ~category:Witness "cannot unassume entry of type %s" target_type + M.warn_noloc ~category:Witness "cannot unassume entry of type %s" target_type in List.iter (fun yaml_entry -> match YamlWitnessType.Entry.of_yaml yaml_entry with | Ok entry -> unassume_entry entry - | Error (`Msg e) -> M.info_noloc ~category:Witness "couldn't parse entry: %s" e + | Error (`Msg e) -> M.error_noloc ~category:Witness "couldn't parse entry: %s" e ) yaml_entries let emit_unassume ctx = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index d9d39ccee1..2969997906 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -829,7 +829,7 @@ struct None | _ -> incr cnt_unsupported; - M.info_noloc ~category:Witness "cannot validate entry of type %s" target_type; + M.warn_noloc ~category:Witness "cannot validate entry of type %s" target_type; None in @@ -841,7 +841,7 @@ struct Option.to_list yaml_certificate_entry @ yaml_entry :: yaml_entries' | Error (`Msg e) -> incr cnt_error; - M.info_noloc ~category:Witness "couldn't parse entry: %s" e; + M.error_noloc ~category:Witness "couldn't parse entry: %s" e; yaml_entry :: yaml_entries' ) [] yaml_entries in From 2e22af7d31bcaaf6ca04e8337f357d2d9282aade Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 15:51:57 +0200 Subject: [PATCH 003/103] Add ghost_variable and ghost_update to YAML witness types --- src/witness/yamlWitness.ml | 19 ++++++++++ src/witness/yamlWitnessType.ml | 68 +++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 2969997906..213dd26f6f 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -141,6 +141,25 @@ struct }; metadata = metadata (); } + + let ghost_variable ~task ~variable ~type_ ~(initial): Entry.t = { + entry_type = GhostVariable { + variable; + scope = "global"; + type_; + initial; + }; + metadata = metadata ~task (); + } + + let ghost_update ~task ~location ~variable ~(expression): Entry.t = { + entry_type = GhostUpdate { + variable; + expression; + location; + }; + metadata = metadata ~task (); + } end let yaml_entries_to_file yaml_entries file = diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index de9fa151d8..6412c3e7b4 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -413,6 +413,60 @@ struct let entry_type = "precondition_loop_invariant_certificate" end +module GhostVariable = +struct + type t = { + variable: string; + scope: string; + type_: string; + initial: string; + } + + let entry_type = "ghost_variable" + + let to_yaml' {variable; scope; type_; initial} = + [ + ("variable", `String variable); + ("scope", `String scope); + ("type", `String type_); + ("initial", `String initial); + ] + + let of_yaml y = + let open GobYaml in + let+ variable = y |> find "variable" >>= to_string + and+ scope = y |> find "scope" >>= to_string + and+ type_ = y |> find "type" >>= to_string + and+ initial = y |> find "initial" >>= to_string in + {variable; scope; type_; initial} +end + +module GhostUpdate = +struct + type t = { + variable: string; + expression: string; + location: Location.t; + (* TODO: branching? *) + } + + let entry_type = "ghost_update" + + let to_yaml' {variable; expression; location} = + [ + ("variable", `String variable); + ("expression", `String expression); + ("location", Location.to_yaml location); + ] + + let of_yaml y = + let open GobYaml in + let+ variable = y |> find "variable" >>= to_string + and+ expression = y |> find "expression" >>= to_string + and+ location = y |> find "location" >>= Location.of_yaml in + {variable; expression; location} +end + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) module EntryType = struct @@ -424,6 +478,8 @@ struct | LoopInvariantCertificate of LoopInvariantCertificate.t | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t | InvariantSet of InvariantSet.t + | GhostVariable of GhostVariable.t + | GhostUpdate of GhostUpdate.t let entry_type = function | LocationInvariant _ -> LocationInvariant.entry_type @@ -433,6 +489,8 @@ struct | LoopInvariantCertificate _ -> LoopInvariantCertificate.entry_type | PreconditionLoopInvariantCertificate _ -> PreconditionLoopInvariantCertificate.entry_type | InvariantSet _ -> InvariantSet.entry_type + | GhostVariable _ -> GhostVariable.entry_type + | GhostUpdate _ -> GhostUpdate.entry_type let to_yaml' = function | LocationInvariant x -> LocationInvariant.to_yaml' x @@ -442,6 +500,8 @@ struct | LoopInvariantCertificate x -> LoopInvariantCertificate.to_yaml' x | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate.to_yaml' x | InvariantSet x -> InvariantSet.to_yaml' x + | GhostVariable x -> GhostVariable.to_yaml' x + | GhostUpdate x -> GhostUpdate.to_yaml' x let of_yaml y = let open GobYaml in @@ -467,8 +527,14 @@ struct else if entry_type = InvariantSet.entry_type then let+ x = y |> InvariantSet.of_yaml in InvariantSet x + else if entry_type = GhostVariable.entry_type then + let+ x = y |> GhostVariable.of_yaml in + GhostVariable x + else if entry_type = GhostUpdate.entry_type then + let+ x = y |> GhostUpdate.of_yaml in + GhostUpdate x else - Error (`Msg "entry_type") + Error (`Msg ("entry_type " ^ entry_type)) end module Entry = From 688c4dc2914897d72bcf8595286d2a49257ebef6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:07:24 +0200 Subject: [PATCH 004/103] Add mutexGhosts analysis --- src/analyses/mutexGhosts.ml | 41 +++++++++++++++++++++++++++++++++++++ src/cdomains/lockDomain.ml | 2 +- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 src/analyses/mutexGhosts.ml diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml new file mode 100644 index 0000000000..fd5f9b5f00 --- /dev/null +++ b/src/analyses/mutexGhosts.ml @@ -0,0 +1,41 @@ +(** ([mutexGhosts]). *) + +open Analyses + + +module Spec = +struct + include UnitAnalysis.Spec + let name () = "mutexGhosts" + + module V = + struct + include Node + let is_write_only _ = true + end + + module Locked = + struct + include LockDomain.Mutexes + let name () = "locked" + end + module Unlocked = + struct + include LockDomain.Mutexes + let name () = "unlocked" + end + module G = Lattice.Prod (Locked) (Unlocked) + + let event ctx e octx = + begin match e with + | Events.Lock (l, _) -> + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot ()) + | Events.Unlock l -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l) + | _ -> () + end; + ctx.local +end + +let _ = + MCP.register_analysis ~dep:["mutexEvents"] (module Spec : MCPSpec) diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index 107c1c0692..a7b3c93571 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -8,7 +8,7 @@ module IdxDom = ValueDomain.IndexDomain open GoblintCil module Mutexes = SetDomain.ToppedSet (Addr) (struct let topname = "All mutexes" end) (* TODO: AD? *) -module Simple = Lattice.Reverse (Mutexes) +module Simple = SetDomain.Reverse (Mutexes) module Priorities = IntDomain.Lifted module Lockset = From 45be1644d407c182fd2919b1403eb09ca3af2413 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:30:09 +0200 Subject: [PATCH 005/103] Add YamlEntryGlobal query --- src/analyses/mCP.ml | 4 ++++ src/domains/queries.ml | 9 +++++++++ src/framework/constraints.ml | 24 ++++++++++++++++++++++++ src/witness/yamlWitness.ml | 20 ++++++++++++++++++++ src/witness/yamlWitnessType.ml | 30 ++++++++++++++++++++++++++++++ 5 files changed, 87 insertions(+) diff --git a/src/analyses/mCP.ml b/src/analyses/mCP.ml index a3943651c0..8f66f8049d 100644 --- a/src/analyses/mCP.ml +++ b/src/analyses/mCP.ml @@ -283,6 +283,10 @@ struct (* InvariantGlobal is special: it only goes to corresponding analysis and the argument variant is unlifted for it *) let (n, g): V.t = Obj.obj g in f ~q:(InvariantGlobal (Obj.repr g)) (Result.top ()) (n, spec n, assoc n ctx.local) + | Queries.YamlEntryGlobal (g, task) -> + (* YamlEntryGlobal is special: it only goes to corresponding analysis and the argument variant is unlifted for it *) + let (n, g): V.t = Obj.obj g in + f ~q:(YamlEntryGlobal (Obj.repr g, task)) (Result.top ()) (n, spec n, assoc n ctx.local) | Queries.PartAccess a -> Obj.repr (access ctx a) | Queries.IterSysVars (vq, fi) -> diff --git a/src/domains/queries.ml b/src/domains/queries.ml index f5fc832a9e..cc63e5fc0d 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -63,6 +63,8 @@ type invariant_context = Invariant.context = { } [@@deriving ord, hash] +module YS = SetDomain.ToppedSet (YamlWitnessType.Entry) (struct let topname = "Top" end) + (** GADT for queries with specific result type. *) type _ t = @@ -126,6 +128,7 @@ type _ t = | MustTermAllLoops: MustBool.t t | IsEverMultiThreaded: MayBool.t t | TmpSpecial: Mval.Exp.t -> ML.t t + | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t type 'a result = 'a @@ -195,6 +198,7 @@ struct | MustTermAllLoops -> (module MustBool) | IsEverMultiThreaded -> (module MayBool) | TmpSpecial _ -> (module ML) + | YamlEntryGlobal _ -> (module YS) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -263,6 +267,7 @@ struct | MustTermAllLoops -> MustBool.top () | IsEverMultiThreaded -> MayBool.top () | TmpSpecial _ -> ML.top () + | YamlEntryGlobal _ -> YS.top () end (* The type any_query can't be directly defined in Any as t, @@ -328,6 +333,7 @@ struct | Any IsEverMultiThreaded -> 55 | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 + | Any (YamlEntryGlobal _) -> 58 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -375,6 +381,7 @@ struct | Any (WarnGlobal vi1), Any (WarnGlobal vi2) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) | Any (Invariant i1), Any (Invariant i2) -> compare_invariant_context i1 i2 | Any (InvariantGlobal vi1), Any (InvariantGlobal vi2) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) + | Any (YamlEntryGlobal (vi1, task1)), Any (YamlEntryGlobal (vi2, task2)) -> Stdlib.compare (Hashtbl.hash vi1) (Hashtbl.hash vi2) (* TODO: compare task *) | Any (IterSysVars (vq1, vf1)), Any (IterSysVars (vq2, vf2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) | Any (MutexType m1), Any (MutexType m2) -> Mval.Unit.compare m1 m2 | Any (MustProtectedVars m1), Any (MustProtectedVars m2) -> compare_mustprotectedvars m1 m2 @@ -418,6 +425,7 @@ struct | Any (Invariant i) -> hash_invariant_context i | Any (MutexType m) -> Mval.Unit.hash m | Any (InvariantGlobal vi) -> Hashtbl.hash vi + | Any (YamlEntryGlobal (vi, task)) -> Hashtbl.hash vi (* TODO: hash task *) | Any (MustProtectedVars m) -> hash_mustprotectedvars m | Any (MayBeModifiedSinceSetjmp e) -> JmpBufDomain.BufferEntry.hash e | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start @@ -474,6 +482,7 @@ struct | Any (WarnGlobal vi) -> Pretty.dprintf "WarnGlobal _" | Any (IterSysVars _) -> Pretty.dprintf "IterSysVars _" | Any (InvariantGlobal i) -> Pretty.dprintf "InvariantGlobal _" + | Any (YamlEntryGlobal (i, task)) -> Pretty.dprintf "YamlEntryGlobal _" | Any (MutexType (v,o)) -> Pretty.dprintf "MutexType _" | Any (EvalMutexAttr a) -> Pretty.dprintf "EvalMutexAttr _" | Any MayAccessed -> Pretty.dprintf "MayAccessed" diff --git a/src/framework/constraints.ml b/src/framework/constraints.ml index 52022b8aee..367386c6f1 100644 --- a/src/framework/constraints.ml +++ b/src/framework/constraints.ml @@ -1250,6 +1250,14 @@ struct | `Right g -> Queries.Result.top q end + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + begin match g with + | `Left g -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr g, task)) + | `Right g -> + Queries.Result.top q + end | IterSysVars (vq, vf) -> (* vars for S *) let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in @@ -1365,6 +1373,14 @@ struct | _ -> Queries.Result.top q end + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + begin match g with + | `Left g -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr g, task)) + | _ -> + Queries.Result.top q + end | IterSysVars (vq, vf) -> (* vars for S *) let vf' x = vf (Obj.repr (V.s (Obj.obj x))) in @@ -1650,6 +1666,14 @@ struct | `Right v -> Queries.Result.top q end + | YamlEntryGlobal (v, task) -> + let v: V.t = Obj.obj v in + begin match v with + | `Left v -> + S.query (conv ctx) (YamlEntryGlobal (Obj.repr v, task)) + | `Right v -> + Queries.Result.top q + end | _ -> S.query (conv ctx) q let branch ctx = S.branch (conv ctx) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 213dd26f6f..6ea8cc6c78 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -359,6 +359,26 @@ struct entries in + (* Generate flow-insensitive invariants *) + let entries = + if true then ( + GHT.fold (fun g v acc -> + match g with + | `Left g -> (* Spec global *) + begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with + | `Lifted _ as inv -> + Queries.YS.fold List.cons inv acc + | `Top -> + acc + end + | `Right _ -> (* contexts global *) + acc + ) gh entries + ) + else + entries + in + (* Generate precondition invariants. We do this in three steps: 1. Collect contexts for each function diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 6412c3e7b4..823fc993ce 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -9,6 +9,7 @@ struct command_line: string option; (* TODO: description *) } + [@@deriving eq, ord, hash] let to_yaml {name; version; command_line} = `O ([ @@ -39,6 +40,7 @@ struct language: string; specification: string option; } + [@@deriving eq, ord, hash] let to_yaml {input_files; input_file_hashes; data_model; language; specification} = `O ([ @@ -78,6 +80,7 @@ struct producer: Producer.t; task: Task.t option; } + [@@deriving eq, ord, hash] let to_yaml {format_version; uuid; creation_time; producer; task} = `O ([ @@ -111,6 +114,7 @@ struct column: int; function_: string; } + [@@deriving eq, ord, hash] let to_yaml {file_name; file_hash; line; column; function_} = `O [ @@ -138,6 +142,7 @@ struct type_: string; format: string; } + [@@deriving eq, ord, hash] let to_yaml {string; type_; format} = `O [ @@ -160,6 +165,7 @@ struct location: Location.t; loop_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "loop_invariant" @@ -182,6 +188,7 @@ struct location: Location.t; location_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "location_invariant" @@ -203,6 +210,7 @@ struct type t = { flow_insensitive_invariant: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "flow_insensitive_invariant" @@ -224,6 +232,7 @@ struct loop_invariant: Invariant.t; precondition: Invariant.t; } + [@@deriving eq, ord, hash] let entry_type = "precondition_loop_invariant" @@ -251,6 +260,7 @@ struct value: string; format: string; } + [@@deriving eq, ord, hash] let invariant_type = "loop_invariant" @@ -282,6 +292,7 @@ struct type t = | LocationInvariant of LocationInvariant.t | LoopInvariant of LoopInvariant.t + [@@deriving eq, ord, hash] let invariant_type = function | LocationInvariant _ -> LocationInvariant.invariant_type @@ -309,6 +320,7 @@ struct type t = { invariant_type: InvariantType.t; } + [@@deriving eq, ord, hash] let to_yaml {invariant_type} = `O [ @@ -327,6 +339,7 @@ struct type t = { content: Invariant.t list; } + [@@deriving eq, ord, hash] let entry_type = "invariant_set" @@ -346,6 +359,7 @@ struct type_: string; file_hash: string; } + [@@deriving eq, ord, hash] let to_yaml {uuid; type_; file_hash} = `O [ @@ -369,6 +383,7 @@ struct type_: string; format: string; } + [@@deriving eq, ord, hash] let to_yaml {string; type_; format} = `O [ @@ -391,6 +406,7 @@ struct target: Target.t; certification: Certification.t; } + [@@deriving eq, ord, hash] let entry_type = "loop_invariant_certificate" @@ -421,6 +437,7 @@ struct type_: string; initial: string; } + [@@deriving eq, ord, hash] let entry_type = "ghost_variable" @@ -449,6 +466,7 @@ struct location: Location.t; (* TODO: branching? *) } + [@@deriving eq, ord, hash] let entry_type = "ghost_update" @@ -480,6 +498,7 @@ struct | InvariantSet of InvariantSet.t | GhostVariable of GhostVariable.t | GhostUpdate of GhostUpdate.t + [@@deriving eq, ord, hash] let entry_type = function | LocationInvariant _ -> LocationInvariant.entry_type @@ -539,10 +558,21 @@ end module Entry = struct + include Printable.StdLeaf + type t = { entry_type: EntryType.t; metadata: Metadata.t; } + [@@deriving eq, ord, hash] + + let name () = "YAML entry" + + let show _ = "TODO" + include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) let to_yaml {entry_type; metadata} = `O ([ From 5d3f5fe61d6d444d23deeb4ff91016689a3d8cfe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 13 Mar 2024 17:38:02 +0200 Subject: [PATCH 006/103] Generate YAML witness ghosts for mutexes --- src/analyses/mutexGhosts.ml | 37 ++++++++++++++++++++++++++++++++++ src/witness/yamlWitness.ml | 7 ++++++- src/witness/yamlWitnessType.ml | 2 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index fd5f9b5f00..fe708b8cac 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -35,6 +35,43 @@ struct | _ -> () end; ctx.local + + let query ctx (type a) (q: a Queries.t): a Queries.result = + match q with + | YamlEntryGlobal (g, task) -> + let g: V.t = Obj.obj g in + let (locked, unlocked) = ctx.global g in + let loc = Node.location g in + let location_function = (Node.find_fundec g).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + let entries = + (* TODO: do ghost_variable-s only once *) + Locked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let type_ = "int" in + let initial = "0" in + let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + Queries.YS.add entry acc + ) (Locked.union locked unlocked) (Queries.YS.empty ()) + in + let entries = + Locked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let expression = "1" in + let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry acc + ) locked entries + in + let entries = + Unlocked.fold (fun l acc -> + let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let expression = "0" in + let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry acc + ) unlocked entries + in + entries + | _ -> Queries.Result.top q end let _ = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 6ea8cc6c78..e04a4c9744 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -367,7 +367,12 @@ struct | `Left g -> (* Spec global *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> - Queries.YS.fold List.cons inv acc + Queries.YS.fold (fun entry acc -> + if BatList.mem_cmp YamlWitnessType.Entry.compare entry acc then (* TODO: be efficient *) + acc + else + entry :: acc + ) inv acc | `Top -> acc end diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 823fc993ce..4bdb730b82 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -562,7 +562,7 @@ struct type t = { entry_type: EntryType.t; - metadata: Metadata.t; + metadata: Metadata.t [@equal fun _ _ -> true] [@compare fun _ _ -> 0] [@hash fun _ -> 1]; } [@@deriving eq, ord, hash] From a80242ae55587538f78e4ff4c3d1b5ee6601a776 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 10:52:05 +0200 Subject: [PATCH 007/103] Make protection privatization more precise with earlyglobs --- src/analyses/basePriv.ml | 4 +-- tests/regression/13-privatized/74-mutex.t | 32 +++++++++++++++++++++++ tests/regression/13-privatized/dune | 2 ++ 3 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/regression/13-privatized/74-mutex.t create mode 100644 tests/regression/13-privatized/dune diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 125429231e..f08e7d710e 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -687,8 +687,8 @@ struct if not invariant then ( if not (Param.handle_atomic && ask.f MustBeAtomic) then sideg (V.unprotected x) v; (* Delay publishing unprotected write in the atomic section. *) - if !earlyglobs then (* earlyglobs workaround for 13/60 *) - sideg (V.protected x) v + if !earlyglobs && not (ThreadFlag.is_currently_multi ask) then (* earlyglobs workaround for 13/60 *) + sideg (V.protected x) v (* Also side to protected because with earlyglobs enter_multithreaded does not side everything to protected *) (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write since W is implicit. *) ); if Param.handle_atomic && ask.f MustBeAtomic then diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t new file mode 100644 index 0000000000..21c89cd524 --- /dev/null +++ b/tests/regression/13-privatized/74-mutex.t @@ -0,0 +1,32 @@ + $ goblint --enable ana.sv-comp.functions 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Should also work with earlyglobs. +Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. + + $ goblint --enable ana.sv-comp.functions --enable exp.earlyglobs 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune new file mode 100644 index 0000000000..23c0dd3290 --- /dev/null +++ b/tests/regression/13-privatized/dune @@ -0,0 +1,2 @@ +(cram + (deps (glob_files *.c))) From 086e60d9dc2c81c718e78f1b444ec63467d7bdf9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 11:51:12 +0200 Subject: [PATCH 008/103] Add ask argument to BasePriv invariant_global-s --- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 14 +++++++------- src/analyses/basePriv.mli | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 9aca9e2079..7c6b2bf73f 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1243,7 +1243,7 @@ struct (* TODO: account for single-threaded values without earlyglobs. *) match g with | `Left g' -> (* priv *) - Priv.invariant_global (priv_getg ctx.global) g' + Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' | `Right _ -> (* thread return *) Invariant.none ) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index f08e7d710e..ea46e25689 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -42,7 +42,7 @@ sig val thread_join: ?force:bool -> Q.ask -> (V.t -> G.t) -> Cil.exp -> BaseComponents (D).t -> BaseComponents (D).t val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> BaseComponents (D).t -> BaseComponents (D).t - val invariant_global: (V.t -> G.t) -> V.t -> Invariant.t + val invariant_global: Q.ask -> (V.t -> G.t) -> V.t -> Invariant.t val invariant_vars: Q.ask -> (V.t -> G.t) -> BaseComponents (D).t -> varinfo list val init: unit -> unit @@ -131,7 +131,7 @@ struct let thread_join ?(force=false) ask get e st = st let thread_return ask get set tid st = st - let invariant_global getg g = + let invariant_global ask getg g = ValueDomain.invariant_global getg g let invariant_vars ask getg st = [] @@ -211,7 +211,7 @@ struct let thread_join ?(force=false) ask get e st = st let thread_return ask get set tid st = st - let invariant_global getg = function + let invariant_global ask getg = function | `Right g' -> (* global *) ValueDomain.invariant_global (read_unprotected_global getg) g' | _ -> (* mutex *) @@ -621,7 +621,7 @@ struct let get_mutex_inits' = CPA.find x get_mutex_inits in VD.join get_mutex_global_x' get_mutex_inits' - let invariant_global getg = function + let invariant_global ask getg = function | `Middle g -> (* global *) ValueDomain.invariant_global (read_unprotected_global getg) g | `Left _ @@ -777,7 +777,7 @@ struct vf (V.protected g); | _ -> () - let invariant_global getg g = + let invariant_global ask getg g = match g with | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' @@ -841,7 +841,7 @@ struct open Locksets - let invariant_global getg = function + let invariant_global ask getg = function | `Right g' -> (* global *) ValueDomain.invariant_global (fun x -> GWeak.fold (fun s' tm acc -> @@ -1633,7 +1633,7 @@ struct let threadenter ask st = time "threadenter" (Priv.threadenter ask) st let threadspawn ask get set st = time "threadspawn" (Priv.threadspawn ask get set) st let iter_sys_vars getg vq vf = time "iter_sys_vars" (Priv.iter_sys_vars getg vq) vf - let invariant_global getg v = time "invariant_global" (Priv.invariant_global getg) v + let invariant_global ask getg v = time "invariant_global" (Priv.invariant_global ask getg) v let invariant_vars ask getg st = time "invariant_vars" (Priv.invariant_vars ask getg) st let thread_join ?(force=false) ask get e st = time "thread_join" (Priv.thread_join ~force ask get e) st diff --git a/src/analyses/basePriv.mli b/src/analyses/basePriv.mli index 6906e6e4e1..e176a450fa 100644 --- a/src/analyses/basePriv.mli +++ b/src/analyses/basePriv.mli @@ -31,7 +31,7 @@ sig val thread_join: ?force:bool -> Queries.ask -> (V.t -> G.t) -> Cil.exp -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t val thread_return: Queries.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> BaseDomain.BaseComponents (D).t -> BaseDomain.BaseComponents (D).t - val invariant_global: (V.t -> G.t) -> V.t -> Invariant.t + val invariant_global: Queries.ask -> (V.t -> G.t) -> V.t -> Invariant.t (** Provides [Queries.InvariantGlobal] result for base. Should account for all unprotected/weak values of global variables. *) From b2d09da76450c1f57909247904bb828f5cf407df Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:07:56 +0200 Subject: [PATCH 009/103] Add MustProtectingLocks query --- src/analyses/mutexAnalysis.ml | 3 +++ src/domains/queries.ml | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 138f65ab47..1d134425f1 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -233,6 +233,9 @@ struct true else *) Mutexes.leq mutex_lockset protecting + | Queries.MustProtectingLocks g -> + let protecting = protecting ~write:true Strong g in + Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index cc63e5fc0d..3fd8c1fc87 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -117,6 +117,7 @@ type _ t = | MustJoinedThreads: ConcDomain.MustThreadSet.t t | ThreadsJoinedCleanly: MustBool.t t | MustProtectedVars: mustprotectedvars -> VS.t t + | MustProtectingLocks: CilType.Varinfo.t -> AD.t t | Invariant: invariant_context -> Invariant.t t | InvariantGlobal: Obj.t -> Invariant.t t (** Argument must be of corresponding [Spec.V.t]. *) | WarnGlobal: Obj.t -> Unit.t t (** Argument must be of corresponding [Spec.V.t]. *) @@ -187,6 +188,7 @@ struct | MustJoinedThreads -> (module ConcDomain.MustThreadSet) | ThreadsJoinedCleanly -> (module MustBool) | MustProtectedVars _ -> (module VS) + | MustProtectingLocks _ -> (module AD) | Invariant _ -> (module Invariant) | InvariantGlobal _ -> (module Invariant) | WarnGlobal _ -> (module Unit) @@ -256,6 +258,7 @@ struct | MustJoinedThreads -> ConcDomain.MustThreadSet.top () | ThreadsJoinedCleanly -> MustBool.top () | MustProtectedVars _ -> VS.top () + | MustProtectingLocks _ -> AD.top () | Invariant _ -> Invariant.top () | InvariantGlobal _ -> Invariant.top () | WarnGlobal _ -> Unit.top () @@ -334,6 +337,7 @@ struct | Any (TmpSpecial _) -> 56 | Any (IsAllocVar _) -> 57 | Any (YamlEntryGlobal _) -> 58 + | Any (MustProtectingLocks _) -> 59 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -385,6 +389,7 @@ struct | Any (IterSysVars (vq1, vf1)), Any (IterSysVars (vq2, vf2)) -> VarQuery.compare vq1 vq2 (* not comparing fs *) | Any (MutexType m1), Any (MutexType m2) -> Mval.Unit.compare m1 m2 | Any (MustProtectedVars m1), Any (MustProtectedVars m2) -> compare_mustprotectedvars m1 m2 + | Any (MustProtectingLocks g1), Any (MustProtectingLocks g2) -> CilType.Varinfo.compare g1 g2 | Any (MayBeModifiedSinceSetjmp e1), Any (MayBeModifiedSinceSetjmp e2) -> JmpBufDomain.BufferEntry.compare e1 e2 | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 @@ -427,6 +432,7 @@ struct | Any (InvariantGlobal vi) -> Hashtbl.hash vi | Any (YamlEntryGlobal (vi, task)) -> Hashtbl.hash vi (* TODO: hash task *) | Any (MustProtectedVars m) -> hash_mustprotectedvars m + | Any (MustProtectingLocks g) -> CilType.Varinfo.hash g | Any (MayBeModifiedSinceSetjmp e) -> JmpBufDomain.BufferEntry.hash e | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv @@ -478,6 +484,7 @@ struct | Any MustJoinedThreads -> Pretty.dprintf "MustJoinedThreads" | Any ThreadsJoinedCleanly -> Pretty.dprintf "ThreadsJoinedCleanly" | Any (MustProtectedVars m) -> Pretty.dprintf "MustProtectedVars _" + | Any (MustProtectingLocks g) -> Pretty.dprintf "MustProtectingLocks _" | Any (Invariant i) -> Pretty.dprintf "Invariant _" | Any (WarnGlobal vi) -> Pretty.dprintf "WarnGlobal _" | Any (IterSysVars _) -> Pretty.dprintf "IterSysVars _" From 526d88aac4ee38d350d8a17b0691766c8dc37e31 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:08:31 +0200 Subject: [PATCH 010/103] Generate protected flow-insensitive invariants with ghosts --- src/analyses/basePriv.ml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index ea46e25689..1863625546 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -777,12 +777,18 @@ struct vf (V.protected g); | _ -> () - let invariant_global ask getg g = + let invariant_global (ask: Q.ask) getg g = match g with | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' - | `Right g -> (* protected *) - Invariant.none + | `Right g' -> (* protected *) + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + let locks = ask.f (Q.MustProtectingLocks g') in + Q.AD.fold (fun m acc -> + let variable = LockDomain.Addr.show m in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(acc || of_exp (Lval (Var var, NoOffset))) + ) locks inv let invariant_vars ask getg st = protected_vars ask end From d536db4708977e10d9946c68fb69effb56e69b24 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:10:20 +0200 Subject: [PATCH 011/103] Make mutex ghost variable names distinct from mutex variables --- src/analyses/basePriv.ml | 2 +- src/analyses/mutexGhosts.ml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 1863625546..c34808522b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -785,7 +785,7 @@ struct let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m in (* TODO: valid C name *) + let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in Invariant.(acc || of_exp (Lval (Var var, NoOffset))) ) locks inv diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index fe708b8cac..1cc3cdca02 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -47,7 +47,7 @@ struct let entries = (* TODO: do ghost_variable-s only once *) Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in @@ -56,7 +56,7 @@ struct in let entries = Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let expression = "1" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -64,7 +64,7 @@ struct in let entries = Unlocked.fold (fun l acc -> - let variable = LockDomain.Addr.show l in (* TODO: valid C name *) + let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) let expression = "0" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc From 2eafa692f26d25897f67748a89b5c1aa9e1e9da1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:26:34 +0200 Subject: [PATCH 012/103] Document MutexGhosts --- src/analyses/mutexGhosts.ml | 2 +- src/goblint_lib.ml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 1cc3cdca02..b8792a2bf8 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -1,4 +1,4 @@ -(** ([mutexGhosts]). *) +(** Analysis for generating ghost variables corresponding to mutexes ([mutexGhosts]). *) open Analyses diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index e06cc8fa08..c0de408f05 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -106,6 +106,7 @@ module MutexAnalysis = MutexAnalysis module MayLocks = MayLocks module SymbLocks = SymbLocks module Deadlock = Deadlock +module MutexGhosts = MutexGhosts (** {3 Threads} From 470ddbc8490d6daaaee397288e328a3f249ca333 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 12:36:15 +0200 Subject: [PATCH 013/103] Fix coverage build --- src/analyses/basePriv.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index c34808522b..a24c686a3a 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -787,7 +787,7 @@ struct Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(acc || of_exp (Lval (Var var, NoOffset))) + Invariant.(acc || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv let invariant_vars ask getg st = protected_vars ask From 0d5ef634d8c2b0bd3adac807b4b65e726e2d03b0 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 13:38:57 +0200 Subject: [PATCH 014/103] Make mutex-meet privatization more precise with earlyglobs --- src/analyses/basePriv.ml | 7 +++-- tests/regression/13-privatized/74-mutex.t | 38 +++++++++++++++++++++-- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index a24c686a3a..6e9384389b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -329,8 +329,11 @@ struct in if not invariant then ( if M.tracing then M.tracel "priv" "WRITE GLOBAL SIDE %a = %a\n" CilType.Varinfo.pretty x VD.pretty v; - sideg (V.global x) (CPA.singleton x v) - (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write. *) + let side_cpa = CPA.singleton x v in + sideg (V.global x) side_cpa; + if !earlyglobs && not (ThreadFlag.is_currently_multi ask) then + sideg V.mutex_inits side_cpa (* Also side to inits because with earlyglobs enter_multithreaded does not side everything to inits *) + (* Unlock after invariant will still side effect refined value (if protected) from CPA, because cannot distinguish from non-invariant write. *) ); {st with cpa = cpa'} (* let write_global ask getg sideg cpa x v = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 21c89cd524..810352de44 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -16,7 +16,41 @@ Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. - $ goblint --enable ana.sv-comp.functions --enable exp.earlyglobs 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable exp.earlyglobs 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Same with mutex-meet. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + +Should also work with earlyglobs. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable exp.earlyglobs 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) From a714dc6d512773c046a1c5dd1f937723623d0c21 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 13:47:17 +0200 Subject: [PATCH 015/103] Generate mutex-meet flow-insensitive invariants with ghosts --- src/analyses/basePriv.ml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 6e9384389b..b28381f9c6 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -294,6 +294,20 @@ module PerMutexMeetPrivBase = struct include PerMutexPrivBase + let invariant_global ask getg = function + | `Left m' as m -> (* mutex *) + let cpa = getg m in + let inv = CPA.fold (fun v _ acc -> + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + ) cpa Invariant.none + in + let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(inv || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + | g -> (* global *) + invariant_global ask getg g + let invariant_vars ask getg (st: _ BaseDomain.basecomponents_t) = (* Mutex-meet local states contain precisely the protected global variables, so we can do fewer queries than {!protected_vars}. *) From 652aeaeaca2c07f03265024ad751ca0a83e41fe5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:02:54 +0200 Subject: [PATCH 016/103] Add ghost variable for multithreaded mode --- src/analyses/base.ml | 11 +++++++++-- src/analyses/mutexGhosts.ml | 28 ++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7c6b2bf73f..7f73fd42af 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1237,13 +1237,20 @@ struct Invariant.none let query_invariant_global ctx g = - if GobConfig.get_bool "ana.base.invariant.enabled" && get_bool "exp.earlyglobs" then ( + if GobConfig.get_bool "ana.base.invariant.enabled" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. Otherwise, the values of globals in single-threaded mode are not accounted for. *) (* TODO: account for single-threaded values without earlyglobs. *) match g with | `Left g' -> (* priv *) - Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' + let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' in + if get_bool "exp.earlyglobs" then + inv + else ( + let variable = "multithreaded" in + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(inv || of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) | `Right _ -> (* thread return *) Invariant.none ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index b8792a2bf8..6a0b8d56e4 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -24,14 +24,21 @@ struct include LockDomain.Mutexes let name () = "unlocked" end - module G = Lattice.Prod (Locked) (Unlocked) + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot ()) + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l) + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) + | Events.EnterMultiThreaded -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) | _ -> () end; ctx.local @@ -40,7 +47,7 @@ struct match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked) = ctx.global g in + let (locked, unlocked, multithread) = ctx.global g in let loc = Node.location g in let location_function = (Node.find_fundec g).svar.vname in let location = YamlWitness.Entry.location ~location:loc ~location_function in @@ -70,6 +77,19 @@ struct Queries.YS.add entry acc ) unlocked entries in + let entries = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + let variable = "multithreaded" in + let type_ = "int" in + let initial = "0" in + let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + let expression = "1" in + let entry' = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries + in entries | _ -> Queries.Result.top q end From 7c33c72abe086f984afa16439af06518063e5ed8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:07:53 +0200 Subject: [PATCH 017/103] Reorder disjuncts in privatized invariants in implication order This also means that the global variable is (lazily) not accessed when the condition isn't met. --- src/analyses/base.ml | 2 +- src/analyses/basePriv.ml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 7f73fd42af..a4e5ab412a 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1249,7 +1249,7 @@ struct else ( let variable = "multithreaded" in let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(inv || of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) | `Right _ -> (* thread return *) Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index b28381f9c6..1950c6219d 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -304,7 +304,7 @@ struct in let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(inv || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) | g -> (* global *) invariant_global ask getg g @@ -804,7 +804,7 @@ struct Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(acc || of_exp (Lval (GoblintCil.var var))) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv let invariant_vars ask getg st = protected_vars ask From 4381e9fafa8108af5baf3d49e6e560fae0e7b7cc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:22:28 +0200 Subject: [PATCH 018/103] Fix MustProtectingLocks query crash with top Happened on 13-privatized/01-priv_nr --- src/analyses/basePriv.ml | 14 +++++++++----- src/analyses/mutexAnalysis.ml | 5 ++++- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 1950c6219d..a26ed3bac3 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -801,11 +801,15 @@ struct | `Right g' -> (* protected *) let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in - Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in - Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) - ) locks inv + if Q.AD.is_top locks then + Invariant.none + else ( + Q.AD.fold (fun m acc -> + let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) + let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) locks inv + ) let invariant_vars ask getg st = protected_vars ask end diff --git a/src/analyses/mutexAnalysis.ml b/src/analyses/mutexAnalysis.ml index 1d134425f1..7e877d7dad 100644 --- a/src/analyses/mutexAnalysis.ml +++ b/src/analyses/mutexAnalysis.ml @@ -235,7 +235,10 @@ struct Mutexes.leq mutex_lockset protecting | Queries.MustProtectingLocks g -> let protecting = protecting ~write:true Strong g in - Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) + if Mutexes.is_top protecting then + Queries.AD.top () + else + Mutexes.fold Queries.AD.add protecting (Queries.AD.empty ()) | Queries.MustLockset -> let held_locks = Lockset.export_locks (Lockset.filter snd ls) in Mutexes.fold (fun addr ls -> Queries.AD.add addr ls) held_locks (Queries.AD.empty ()) From 60a51b986900e2efa77924fb6fb83c689e6917f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:27:01 +0200 Subject: [PATCH 019/103] Fix protection privatization protected invariant with no protecting mutexes Happened on 13-privatized/02-priv_rc. --- src/analyses/basePriv.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index a26ed3bac3..891e8d2183 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -799,11 +799,11 @@ struct | `Left g' -> (* unprotected *) ValueDomain.invariant_global (fun g -> getg (V.unprotected g)) g' | `Right g' -> (* protected *) - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) let locks = ask.f (Q.MustProtectingLocks g') in - if Q.AD.is_top locks then + if Q.AD.is_top locks || Q.AD.is_empty locks then Invariant.none else ( + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in From fd84cd95f93b82b0f062e82f5683b011a52fc09e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 14 Mar 2024 17:31:19 +0200 Subject: [PATCH 020/103] Fix mutex-meet privatization protected invariant with no protecting mutexes Happened on 13-privatized/02-priv_rc. --- src/analyses/basePriv.ml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 891e8d2183..94f0f4092b 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -294,12 +294,15 @@ module PerMutexMeetPrivBase = struct include PerMutexPrivBase - let invariant_global ask getg = function + let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) let cpa = getg m in let inv = CPA.fold (fun v _ acc -> - let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in - Invariant.(acc && inv) + if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + else + acc ) cpa Invariant.none in let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) From 516e3adc1128fef03ec49ec9bb1b03814914f462 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 12:31:06 +0200 Subject: [PATCH 021/103] Use RichVarinfo for witness ghost variables --- src/analyses/base.ml | 3 +-- src/analyses/basePriv.ml | 6 ++---- src/analyses/mutexGhosts.ml | 8 ++++---- src/goblint_lib.ml | 1 + src/witness/witnessGhost.ml | 21 +++++++++++++++++++++ 5 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 src/witness/witnessGhost.ml diff --git a/src/analyses/base.ml b/src/analyses/base.ml index a4e5ab412a..7ba0d5f706 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,8 +1247,7 @@ struct if get_bool "exp.earlyglobs" then inv else ( - let variable = "multithreaded" in - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo Multithreaded in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) | `Right _ -> (* thread return *) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 94f0f4092b..deb603a110 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -305,8 +305,7 @@ struct acc ) cpa Invariant.none in - let variable = LockDomain.Addr.show m' ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) | g -> (* global *) invariant_global ask getg g @@ -808,8 +807,7 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - let variable = LockDomain.Addr.show m ^ "_locked" in (* TODO: valid C name *) - let var = Cilfacade.create_var (GoblintCil.makeGlobalVar variable GoblintCil.intType) in + let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) locks inv ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6a0b8d56e4..aedbeac0d4 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -54,7 +54,7 @@ struct let entries = (* TODO: do ghost_variable-s only once *) Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in @@ -63,7 +63,7 @@ struct in let entries = Locked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let expression = "1" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -71,7 +71,7 @@ struct in let entries = Unlocked.fold (fun l acc -> - let variable = LockDomain.Addr.show l ^ "_locked" in (* TODO: valid C name *) + let variable = WitnessGhost.name_varinfo (Locked l) in let expression = "0" in let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in Queries.YS.add entry acc @@ -79,7 +79,7 @@ struct in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let variable = "multithreaded" in + let variable = WitnessGhost.name_varinfo Multithreaded in let type_ = "int" in let initial = "0" in let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in diff --git a/src/goblint_lib.ml b/src/goblint_lib.ml index c0de408f05..18a5d72aa7 100644 --- a/src/goblint_lib.ml +++ b/src/goblint_lib.ml @@ -333,6 +333,7 @@ module Graphml = Graphml module YamlWitness = YamlWitness module YamlWitnessType = YamlWitnessType +module WitnessGhost = WitnessGhost module WideningTokens = WideningTokens (** {3 Violation} diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml new file mode 100644 index 0000000000..a9d177a569 --- /dev/null +++ b/src/witness/witnessGhost.ml @@ -0,0 +1,21 @@ +(** Ghost variables for YAML witnesses. *) + +module Var = +struct + type t = + | Locked of LockDomain.Addr.t + | Multithreaded + [@@deriving eq, hash] + + let name_varinfo = function + | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) + | Multithreaded -> "multithreaded" + + (* TODO: define correct types *) +end + +include Var + +module Map = RichVarinfo.Make (Var) + +include Map From a10c973d2712c7b36a28fb176f72fcf99117e958 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 12:54:52 +0200 Subject: [PATCH 022/103] Deduplicate witness ghost entry creation --- src/analyses/mutexGhosts.ml | 26 ++++++-------------------- src/witness/witnessGhost.ml | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index aedbeac0d4..0b11355d57 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -48,43 +48,29 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in let (locked, unlocked, multithread) = ctx.global g in - let loc = Node.location g in - let location_function = (Node.find_fundec g).svar.vname in - let location = YamlWitness.Entry.location ~location:loc ~location_function in let entries = - (* TODO: do ghost_variable-s only once *) + (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let type_ = "int" in - let initial = "0" in - let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in + let entry = WitnessGhost.variable_entry ~task (Locked l) in Queries.YS.add entry acc ) (Locked.union locked unlocked) (Queries.YS.empty ()) in let entries = Locked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let expression = "1" in - let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in Queries.YS.add entry acc ) locked entries in let entries = Unlocked.fold (fun l acc -> - let variable = WitnessGhost.name_varinfo (Locked l) in - let expression = "0" in - let entry = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let variable = WitnessGhost.name_varinfo Multithreaded in - let type_ = "int" in - let initial = "0" in - let entry = YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial in - let expression = "1" in - let entry' = YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression in + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in Queries.YS.add entry (Queries.YS.add entry' entries) ) else diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index a9d177a569..dd4181e467 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -12,6 +12,14 @@ struct | Multithreaded -> "multithreaded" (* TODO: define correct types *) + + let type_ = function + | Locked _ -> GoblintCil.intType + | Multithreaded -> GoblintCil.intType + + let initial = function + | Locked _ -> GoblintCil.zero + | Multithreaded -> GoblintCil.zero end include Var @@ -19,3 +27,17 @@ include Var module Map = RichVarinfo.Make (Var) include Map + +let variable_entry ~task x = + let variable = name_varinfo x in + let type_ = String.trim (CilType.Typ.show (type_ x)) in (* CIL printer puts space at the end of some types *) + let initial = CilType.Exp.show (initial x) in + YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial + +let update_entry ~task ~node x e = + let loc = Node.location node in + let location_function = (Node.find_fundec node).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + let variable = name_varinfo x in + let expression = CilType.Exp.show e in + YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression From 932ac3b312a77d09a683fa651ab114e30aec1b1e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 15 Mar 2024 13:00:59 +0200 Subject: [PATCH 023/103] Allow non-void types for RichVarinfo --- src/analyses/basePriv.ml | 2 +- src/analyses/wrapperFunctionAnalysis.ml | 2 ++ src/common/util/richVarinfo.ml | 9 +++++---- src/common/util/richVarinfo.mli | 3 ++- src/witness/witnessGhost.ml | 6 ++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index deb603a110..cafa84eb79 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -951,7 +951,7 @@ struct (* sync: M -> (2^M -> (G -> D)) *) include AbstractLockCenteredBase (ThreadMap) (LockCenteredBase.CPA) - let global_init_thread = RichVarinfo.single ~name:"global_init" + let global_init_thread = RichVarinfo.single ~name:"global_init" ~typ:GoblintCil.voidType let current_thread (ask: Q.ask): Thread.t = if !AnalysisState.global_initialization then ThreadIdDomain.Thread.threadinit (global_init_thread ()) ~multiple:false diff --git a/src/analyses/wrapperFunctionAnalysis.ml b/src/analyses/wrapperFunctionAnalysis.ml index 9510304e56..f3cf05c94d 100644 --- a/src/analyses/wrapperFunctionAnalysis.ml +++ b/src/analyses/wrapperFunctionAnalysis.ml @@ -144,6 +144,8 @@ module MallocWrapper : MCPSpec = struct Format.dprintf "@tid:%s" (ThreadLifted.show t) in Format.asprintf "(alloc@sid:%s%t%t)" (Node.show_id node) tid uniq_count + + let typ _ = GoblintCil.voidType end module NodeVarinfoMap = RichVarinfo.BiVarinfoMap.Make(ThreadNode) diff --git a/src/common/util/richVarinfo.ml b/src/common/util/richVarinfo.ml index d1918c40a6..6a27339eed 100644 --- a/src/common/util/richVarinfo.ml +++ b/src/common/util/richVarinfo.ml @@ -1,9 +1,9 @@ open GoblintCil -let create_var name = Cilfacade.create_var @@ makeGlobalVar name voidType +let create_var name typ = Cilfacade.create_var @@ makeGlobalVar name typ -let single ~name = - let vi = lazy (create_var name) in +let single ~name ~typ = + let vi = lazy (create_var name typ) in fun () -> Lazy.force vi @@ -21,6 +21,7 @@ module type G = sig include Hashtbl.HashedType val name_varinfo: t -> string + val typ: t -> typ end module type H = @@ -47,7 +48,7 @@ struct try XH.find !xh x with Not_found -> - let vi = create_var (X.name_varinfo x) in + let vi = create_var (X.name_varinfo x) (X.typ x) in store_f x vi; vi diff --git a/src/common/util/richVarinfo.mli b/src/common/util/richVarinfo.mli index 4e682734ee..d1c002bf84 100644 --- a/src/common/util/richVarinfo.mli +++ b/src/common/util/richVarinfo.mli @@ -2,7 +2,7 @@ open GoblintCil -val single: name:string -> (unit -> varinfo) +val single: name:string -> typ:typ -> (unit -> varinfo) module type VarinfoMap = sig @@ -18,6 +18,7 @@ module type G = sig include Hashtbl.HashedType val name_varinfo: t -> string + val typ: t -> typ end module type H = diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index dd4181e467..a0d25c5be6 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -11,9 +11,7 @@ struct | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) | Multithreaded -> "multithreaded" - (* TODO: define correct types *) - - let type_ = function + let typ = function | Locked _ -> GoblintCil.intType | Multithreaded -> GoblintCil.intType @@ -30,7 +28,7 @@ include Map let variable_entry ~task x = let variable = name_varinfo x in - let type_ = String.trim (CilType.Typ.show (type_ x)) in (* CIL printer puts space at the end of some types *) + let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) let initial = CilType.Exp.show (initial x) in YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial From b0182659a02387cb57a32c67f65a4fa9331b4821 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 12:19:24 +0300 Subject: [PATCH 024/103] Add cram test for privatized witness ghosts --- tests/regression/13-privatized/74-mutex.t | 142 +++++++++++++++++++++- 1 file changed, 140 insertions(+), 2 deletions(-) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 810352de44..1be888426c 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -7,12 +7,81 @@ dead: 1 total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 0 total memory locations: 1 + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 4 + function: producer + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 4 + function: producer + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. @@ -33,7 +102,7 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -42,12 +111,81 @@ Same with mutex-meet. dead: 1 total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 unsafe: 0 total memory locations: 1 + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "1" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 4 + function: producer + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 2 + function: main + - entry_type: ghost_update + variable: m_locked + expression: "0" + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 4 + function: producer + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Should also work with earlyglobs. $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable exp.earlyglobs 74-mutex.c From 7992462268c057f2a26a1f5cfeeab7c0c704e5e4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 13:42:29 +0300 Subject: [PATCH 025/103] Add cram test for witness ghosts with multiple protecting locks --- .../56-witness/64-ghost-multiple-protecting.c | 30 ++ .../56-witness/64-ghost-multiple-protecting.t | 450 ++++++++++++++++++ 2 files changed, 480 insertions(+) create mode 100644 tests/regression/56-witness/64-ghost-multiple-protecting.c create mode 100644 tests/regression/56-witness/64-ghost-multiple-protecting.t diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c new file mode 100644 index 0000000000..0485cd124e --- /dev/null +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -0,0 +1,30 @@ +#include + +int g1, g2; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + + pthread_mutex_lock(&m1); + pthread_mutex_lock(&m2); + g2 = 1; + pthread_mutex_unlock(&m2); + pthread_mutex_lock(&m2); + g2 = 0; + pthread_mutex_unlock(&m2); + pthread_mutex_unlock(&m1); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + return 0; +} diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t new file mode 100644 index 0000000000..7a413332a2 --- /dev/null +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -0,0 +1,450 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + +protection doesn't have precise protected invariant for g2. + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || (0 <= g2 && g2 <= 1)))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + +protection-read has precise protected invariant for g2. + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g2 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 18 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 28 + column: 2 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 21 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 18 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 12 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 15 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 8 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 2 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 2 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || ((0 <= g2 && g2 <= 1) && g1 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || (g1 == 0 && g2 == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From 01c9b98fc839e3591d2111b279a99765e34af6ff Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 2 Apr 2024 14:55:35 +0300 Subject: [PATCH 026/103] mutex-meet ghost invariants are maybe unsound --- .../56-witness/64-ghost-multiple-protecting.c | 11 +++ .../56-witness/64-ghost-multiple-protecting.t | 68 ++++++++++--------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 0485cd124e..b19ab18ad5 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,4 +1,5 @@ #include +#include int g1, g2; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; @@ -26,5 +27,15 @@ void *t_fun(void *arg) { int main() { pthread_t id; pthread_create(&id, NULL, t_fun, NULL); + + /* pthread_mutex_lock(&m1); + __goblint_check(g1 == 0); + __goblint_check(g2 == 0); + pthread_mutex_unlock(&m1); + + pthread_mutex_lock(&m2); + __goblint_check(g1 == 0); + __goblint_check(g2 == 0); + pthread_mutex_unlock(&m2); */ return 0; } diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 7a413332a2..b221d65ef1 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -20,7 +20,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -29,7 +29,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -38,7 +38,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -47,7 +47,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -56,7 +56,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -65,7 +65,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -74,7 +74,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -83,7 +83,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -92,7 +92,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -101,7 +101,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -110,7 +110,7 @@ protection doesn't have precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable @@ -171,7 +171,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -180,7 +180,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -189,7 +189,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -198,7 +198,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -207,7 +207,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -216,7 +216,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -225,7 +225,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -234,7 +234,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -243,7 +243,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -252,7 +252,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -261,7 +261,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable @@ -313,6 +313,8 @@ protection-read has precise protected invariant for g2. unsafe: 0 total memory locations: 2 +TODO: Are the mutex-meet invariants sound? + $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -320,7 +322,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 28 + line: 29 column: 2 function: main - entry_type: ghost_update @@ -329,7 +331,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 19 + line: 20 column: 2 function: t_fun - entry_type: ghost_update @@ -338,7 +340,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 16 + line: 17 column: 2 function: t_fun - entry_type: ghost_update @@ -347,7 +349,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 9 + line: 10 column: 2 function: t_fun - entry_type: ghost_update @@ -356,7 +358,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 21 + line: 22 column: 2 function: t_fun - entry_type: ghost_update @@ -365,7 +367,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 18 + line: 19 column: 2 function: t_fun - entry_type: ghost_update @@ -374,7 +376,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 12 + line: 13 column: 2 function: t_fun - entry_type: ghost_update @@ -383,7 +385,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 15 + line: 16 column: 2 function: t_fun - entry_type: ghost_update @@ -392,7 +394,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 8 + line: 9 column: 2 function: t_fun - entry_type: ghost_update @@ -401,7 +403,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 22 + line: 23 column: 2 function: t_fun - entry_type: ghost_update @@ -410,7 +412,7 @@ protection-read has precise protected invariant for g2. location: file_name: 64-ghost-multiple-protecting.c file_hash: $FILE_HASH - line: 13 + line: 14 column: 2 function: t_fun - entry_type: ghost_variable From d3a5a0a3f1f864652788ed6852a019566efead3a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 4 Apr 2024 17:05:34 +0300 Subject: [PATCH 027/103] Add NOWARNs to commented out checks in 56-witness/64-ghost-multiple-protecting --- .../regression/56-witness/64-ghost-multiple-protecting.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index b19ab18ad5..012318ac49 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -29,13 +29,13 @@ int main() { pthread_create(&id, NULL, t_fun, NULL); /* pthread_mutex_lock(&m1); - __goblint_check(g1 == 0); - __goblint_check(g2 == 0); + __goblint_check(g1 == 0); // NOWARN (commented out) + __goblint_check(g2 == 0); // NOWARN (commented out) pthread_mutex_unlock(&m1); pthread_mutex_lock(&m2); - __goblint_check(g1 == 0); - __goblint_check(g2 == 0); + __goblint_check(g1 == 0); // NOWARN (commented out) + __goblint_check(g2 == 0); // NOWARN (commented out) pthread_mutex_unlock(&m2); */ return 0; } From 612c1ccd4fe756af60fde77d837781fe800493ae Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 12:37:18 +0300 Subject: [PATCH 028/103] Remove TODO about mutex-meet unsound witness invariants --- tests/regression/56-witness/64-ghost-multiple-protecting.t | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index b221d65ef1..619438b3e3 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -313,8 +313,6 @@ protection-read has precise protected invariant for g2. unsafe: 0 total memory locations: 2 -TODO: Are the mutex-meet invariants sound? - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded From e235ba70d1b187a0395f83729ef53f667fc41e6e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 16:25:14 +0300 Subject: [PATCH 029/103] Rewrite mutexGhosts with may locksets per node This makes 56-witness/65-ghost-ambiguous-lock have sensible ghost updates. --- src/analyses/mutexGhosts.ml | 83 +++++---- tests/regression/13-privatized/74-mutex.c | 4 +- tests/regression/13-privatized/74-mutex.t | 20 +-- .../56-witness/64-ghost-multiple-protecting.t | 6 +- .../56-witness/65-ghost-ambiguous-lock.c | 44 +++++ .../56-witness/65-ghost-ambiguous-lock.t | 166 ++++++++++++++++++ 6 files changed, 278 insertions(+), 45 deletions(-) create mode 100644 tests/regression/56-witness/65-ghost-ambiguous-lock.c create mode 100644 tests/regression/56-witness/65-ghost-ambiguous-lock.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 0b11355d57..ad40915e7f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -5,49 +5,72 @@ open Analyses module Spec = struct - include UnitAnalysis.Spec - let name () = "mutexGhosts" - - module V = + (* Copied & modified from MayLocks. *) + module Arg = struct - include Node - let is_write_only _ = true - end + module D = LockDomain.MayLocksetNoRW + module V = + struct + include Node + let is_write_only _ = true + end - module Locked = - struct - include LockDomain.Mutexes - let name () = "locked" - end - module Unlocked = - struct - include LockDomain.Mutexes - let name () = "unlocked" - end - module MultiThread = - struct - include BoolDomain.MayBool - let name () = "multithread" + module Locked = + struct + include D + let name () = "locked" + end + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod (Locked) (MultiThread) + + let add ctx (l,r) = + D.add l ctx.local + + let remove ctx l = + match D.Addr.to_mval l with + | Some (v,o) -> + (let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in + match mtype with + | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local + | _ -> ctx.local (* we cannot remove them here *)) + | None -> ctx.local (* we cannot remove them here *) end - module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) + + include LocksetAnalysis.MakeMay (Arg) + let name () = "mutexGhosts" + + open Arg + + let sync ctx reason = + if !AnalysisState.postsolving then + ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()); + ctx.local let event ctx e octx = begin match e with - | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) - | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) + ctx.sideg ctx.prev_node (Locked.bot (), true) | _ -> () end; - ctx.local + event ctx e octx (* delegate to must lockset analysis *) let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked, multithread) = ctx.global g in + let module Cfg = (val !MyCFG.current_cfg) in + let next_lockset = List.fold_left (fun acc (_, next_node) -> + let (locked, _) = ctx.global next_node in + D.join acc locked + ) (D.bot ()) (Cfg.next g) + in + let (lockset, multithread) = ctx.global g in + let unlocked = D.diff lockset next_lockset in + let locked = D.diff next_lockset lockset in let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> @@ -62,7 +85,7 @@ struct ) locked entries in let entries = - Unlocked.fold (fun l acc -> + Locked.fold (fun l acc -> let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries diff --git a/tests/regression/13-privatized/74-mutex.c b/tests/regression/13-privatized/74-mutex.c index 8ed9448b7b..7c57688238 100644 --- a/tests/regression/13-privatized/74-mutex.c +++ b/tests/regression/13-privatized/74-mutex.c @@ -29,8 +29,8 @@ void* producer() int main() { pthread_t tid; - - pthread_mutex_init(&m, 0); + pthread_mutexattr_t mutexattr; pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL); + pthread_mutex_init(&m, &mutexattr); pthread_create(&tid, 0, producer, 0); pthread_mutex_lock(&m); diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index d6d7c237e4..6f84aa184f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,11 +1,11 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -90,9 +90,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 @@ -102,14 +102,14 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -193,9 +193,9 @@ Should also work with earlyglobs. [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 14 + live: 15 dead: 1 - total lines: 15 + total lines: 16 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 17a0a3c600..d51db2285e 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -149,7 +149,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -300,7 +300,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.c b/tests/regression/56-witness/65-ghost-ambiguous-lock.c new file mode 100644 index 0000000000..b1df0ee2e8 --- /dev/null +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.c @@ -0,0 +1,44 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +#include +#include + +int g1, g2; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m1); + pthread_mutex_lock(&m2); + g2 = 1; + g2 = 0; + pthread_mutex_unlock(&m2); + return NULL; +} + +void fun(pthread_mutex_t *m) { + pthread_mutex_lock(m); + // what g2 can read? + pthread_mutex_unlock(m); +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_t *m; + int r; // rand + m = r ? &m1 : &m2; + + pthread_mutex_lock(m); + // what g1 can read? + pthread_mutex_unlock(m); + + if (r) + fun(&m1); + else + fun(&m2); + return 0; +} diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t new file mode 100644 index 0000000000..ee586bd531 --- /dev/null +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -0,0 +1,166 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 65-ghost-ambiguous-lock.c + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 23 + dead: 0 + total lines: 23 + [Info][Witness] witness generation summary: + total generation entries: 20 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || g2 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g1 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From 726f646eb85ed399955cf11d78c60db56217b9d4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 17:49:52 +0300 Subject: [PATCH 030/103] Add test for mutex ghosts for alloc variables --- .../56-witness/66-ghost-alloc-lock.c | 37 +++++ .../56-witness/66-ghost-alloc-lock.t | 134 ++++++++++++++++++ 2 files changed, 171 insertions(+) create mode 100644 tests/regression/56-witness/66-ghost-alloc-lock.c create mode 100644 tests/regression/56-witness/66-ghost-alloc-lock.t diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c new file mode 100644 index 0000000000..75d405f1ab --- /dev/null +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -0,0 +1,37 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 +#include +#include + +int g1, g2; +pthread_mutex_t *m1; +pthread_mutex_t *m2; + +void *t_fun(void *arg) { + pthread_mutex_lock(m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(m1); + pthread_mutex_lock(m2); + g2 = 1; + g2 = 0; + pthread_mutex_unlock(m2); + return NULL; +} + +int main() { + m1 = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(m1, NULL); + m2 = malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(m2, NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(m1); + __goblint_check(g1 == 0); + pthread_mutex_unlock(m1); + pthread_mutex_lock(m2); + __goblint_check(g2 == 0); + pthread_mutex_unlock(m2); + return 0; +} diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t new file mode 100644 index 0000000000..84c1589317 --- /dev/null +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -0,0 +1,134 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 66-ghost-alloc-lock.c + [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) + [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 23 + dead: 0 + total lines: 23 + [Info][Witness] witness generation summary: + total generation entries: 16 + [Info][Race] Memory locations race summary: + safe: 4 + vulnerable: 0 + unsafe: 0 + total memory locations: 4 + +TODO: valid C names for alloc mutex ghosts + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 33 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 36 + column: 10 + function: main + - entry_type: ghost_update + variable: (alloc@sid:14@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 18 + column: 10 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "1" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 36 + column: 10 + function: main + - entry_type: ghost_update + variable: (alloc@sid:11@tid:[main](#0))_locked + expression: "0" + location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 18 + column: 10 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: (alloc@sid:14@tid:[main](#0))_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: (alloc@sid:11@tid:[main](#0))_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g2 && g2 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((alloc@sid:14@tid:[main](#0))_locked || g2 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((alloc@sid:11@tid:[main](#0))_locked || g1 == 0)' + type: assertion + format: C From 3e9d7c32daffe2f818e5fa5ebf81b5a459fb40bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 15 Apr 2024 18:05:38 +0300 Subject: [PATCH 031/103] Add valid names to alloc mutex ghosts --- src/witness/witnessGhost.ml | 10 ++++++- .../56-witness/66-ghost-alloc-lock.t | 30 +++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index a0d25c5be6..2aca886e78 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -8,7 +8,15 @@ struct [@@deriving eq, hash] let name_varinfo = function - | Locked l -> LockDomain.Addr.show l ^ "_locked" (* TODO: valid C name *) + | Locked (Addr (v, _) as l) -> + let name = + if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then + Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) + else + LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + in + name ^ "_locked" + | Locked _ -> assert false | Multithreaded -> "multithreaded" let typ = function diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index 84c1589317..bc3236d5a9 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -13,8 +13,6 @@ unsafe: 0 total memory locations: 4 -TODO: valid C names for alloc mutex ghosts - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -26,7 +24,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -35,7 +33,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -44,7 +42,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -53,7 +51,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: main - entry_type: ghost_update - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -62,7 +60,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -71,7 +69,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: main - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -80,7 +78,7 @@ TODO: valid C names for alloc mutex ghosts column: 3 function: t_fun - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -89,7 +87,7 @@ TODO: valid C names for alloc mutex ghosts column: 10 function: main - entry_type: ghost_update - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -103,32 +101,32 @@ TODO: valid C names for alloc mutex ghosts type: int initial: "0" - entry_type: ghost_variable - variable: (alloc@sid:14@tid:[main](#0))_locked + variable: alloc_m861095507_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: (alloc@sid:11@tid:[main](#0))_locked + variable: alloc_m559918035_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (0 <= g2 && g2 <= 1)' + string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (0 <= g1 && g1 <= 1)' + string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || ((alloc@sid:14@tid:[main](#0))_locked || g2 == 0)' + string: '! multithreaded || (0 <= g2 && g2 <= 1)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || ((alloc@sid:11@tid:[main](#0))_locked || g1 == 0)' + string: '! multithreaded || (0 <= g1 && g1 <= 1)' type: assertion format: C From b19cc2d23ae27f5692c69da724caa703a0e12660 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 14:01:42 +0300 Subject: [PATCH 032/103] Fix mutexGhosts indentation --- src/analyses/mutexGhosts.ml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index ad40915e7f..1c1a05b3b7 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -33,10 +33,11 @@ struct let remove ctx l = match D.Addr.to_mval l with | Some (v,o) -> - (let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in - match mtype with - | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local - | _ -> ctx.local (* we cannot remove them here *)) + let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in + begin match mtype with + | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local + | _ -> ctx.local (* we cannot remove them here *) + end | None -> ctx.local (* we cannot remove them here *) end From 885d0cf4b96d3aec64d90d68cd27e82867001f2a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 14:03:09 +0300 Subject: [PATCH 033/103] Use non-recursive mutex in 56-witness/66-ghost-alloc-lock This fixes unlock ghost update locations. --- .../56-witness/66-ghost-alloc-lock.c | 6 +-- .../56-witness/66-ghost-alloc-lock.t | 40 +++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c index 75d405f1ab..2c1028564a 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.c +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -18,11 +18,11 @@ void *t_fun(void *arg) { return NULL; } -int main() { +int main() { pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); // https://github.com/goblint/analyzer/pull/1414 m1 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m1, NULL); + pthread_mutex_init(m1, &attr); m2 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m2, NULL); + pthread_mutex_init(m2, &attr); pthread_t id; pthread_create(&id, NULL, t_fun, NULL); diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index bc3236d5a9..e4d128b71e 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -24,7 +24,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -33,7 +33,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -42,25 +42,25 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 36 - column: 10 + line: 35 + column: 3 function: main - entry_type: ghost_update - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 18 - column: 10 + line: 17 + column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -69,7 +69,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -78,22 +78,22 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 36 - column: 10 + line: 32 + column: 3 function: main - entry_type: ghost_update - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c file_hash: $FILE_HASH - line: 18 - column: 10 + line: 13 + column: 3 function: t_fun - entry_type: ghost_variable variable: multithreaded @@ -101,23 +101,23 @@ type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m861095507_locked + variable: alloc_m817990718_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m559918035_locked + variable: alloc_m334174073_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' + string: '! multithreaded || (alloc_m817990718_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' + string: '! multithreaded || (alloc_m334174073_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant From 21ae83a40215d181e92d31fa81b962c0937b0534 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 16 Apr 2024 17:22:50 +0300 Subject: [PATCH 034/103] Fix mutexGhosts unlocking everything at function return --- src/analyses/mutexGhosts.ml | 21 ++++-- .../56-witness/67-ghost-no-unlock.c | 27 +++++++ .../56-witness/67-ghost-no-unlock.t | 71 +++++++++++++++++++ 3 files changed, 112 insertions(+), 7 deletions(-) create mode 100644 tests/regression/56-witness/67-ghost-no-unlock.c create mode 100644 tests/regression/56-witness/67-ghost-no-unlock.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 1c1a05b3b7..934b2a0c0e 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -47,8 +47,11 @@ struct open Arg let sync ctx reason = - if !AnalysisState.postsolving then - ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()); + if !AnalysisState.postsolving then ( + match reason with + | `Return -> ctx.sideg ctx.node (ctx.local, MultiThread.bot ()) + | _ -> ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()) + ); ctx.local let event ctx e octx = @@ -64,12 +67,16 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in let module Cfg = (val !MyCFG.current_cfg) in - let next_lockset = List.fold_left (fun acc (_, next_node) -> - let (locked, _) = ctx.global next_node in - D.join acc locked - ) (D.bot ()) (Cfg.next g) - in let (lockset, multithread) = ctx.global g in + let next_lockset = + match Cfg.next g with + | [] -> lockset (* HACK for return nodes *) + | nexts -> + List.fold_left (fun acc (_, next_node) -> + let (locked, _) = ctx.global next_node in + D.join acc locked + ) (D.bot ()) nexts + in let unlocked = D.diff lockset next_lockset in let locked = D.diff next_lockset lockset in let entries = diff --git a/tests/regression/56-witness/67-ghost-no-unlock.c b/tests/regression/56-witness/67-ghost-no-unlock.c new file mode 100644 index 0000000000..fc10b919d0 --- /dev/null +++ b/tests/regression/56-witness/67-ghost-no-unlock.c @@ -0,0 +1,27 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +#include +#include + +int g1; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m1); + g1 = 1; + g1 = 0; + pthread_mutex_unlock(&m1); + return NULL; +} + +int main() { + + + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + + pthread_mutex_lock(&m1); + __goblint_check(g1 == 0); + // no unlock + return 0; // there should be no ghost updates for unlock here +} diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t new file mode 100644 index 0000000000..491dd9cf44 --- /dev/null +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -0,0 +1,71 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 67-ghost-no-unlock.c + [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 11 + dead: 0 + total lines: 11 + [Info][Witness] witness generation summary: + total generation entries: 8 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 12 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g1 == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g1 && g1 <= 1)' + type: assertion + format: C From d67c083ba9755e6d1ecc38daaf28d3a266a1ee38 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Apr 2024 14:49:58 +0300 Subject: [PATCH 035/103] Revert "Rewrite mutexGhosts with may locksets per node" This partially reverts commits e235ba70d1b187a0395f83729ef53f667fc41e6e and 21ae83a40215d181e92d31fa81b962c0937b0534. --- src/analyses/mutexGhosts.ml | 91 ++++++++++++------------------------- 1 file changed, 30 insertions(+), 61 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 934b2a0c0e..0b11355d57 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -5,80 +5,49 @@ open Analyses module Spec = struct - (* Copied & modified from MayLocks. *) - module Arg = - struct - module D = LockDomain.MayLocksetNoRW - module V = - struct - include Node - let is_write_only _ = true - end - - module Locked = - struct - include D - let name () = "locked" - end - module MultiThread = - struct - include BoolDomain.MayBool - let name () = "multithread" - end - module G = Lattice.Prod (Locked) (MultiThread) - - let add ctx (l,r) = - D.add l ctx.local - - let remove ctx l = - match D.Addr.to_mval l with - | Some (v,o) -> - let mtype = ctx.ask (Queries.MutexType (v, Offset.Unit.of_offs o)) in - begin match mtype with - | `Lifted MutexAttrDomain.MutexKind.NonRec -> D.remove l ctx.local - | _ -> ctx.local (* we cannot remove them here *) - end - | None -> ctx.local (* we cannot remove them here *) - end - - include LocksetAnalysis.MakeMay (Arg) + include UnitAnalysis.Spec let name () = "mutexGhosts" - open Arg + module V = + struct + include Node + let is_write_only _ = true + end - let sync ctx reason = - if !AnalysisState.postsolving then ( - match reason with - | `Return -> ctx.sideg ctx.node (ctx.local, MultiThread.bot ()) - | _ -> ctx.sideg ctx.prev_node (ctx.local, MultiThread.bot ()) - ); - ctx.local + module Locked = + struct + include LockDomain.Mutexes + let name () = "locked" + end + module Unlocked = + struct + include LockDomain.Mutexes + let name () = "unlocked" + end + module MultiThread = + struct + include BoolDomain.MayBool + let name () = "multithread" + end + module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) let event ctx e octx = begin match e with + | Events.Lock (l, _) -> + ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) + | Events.Unlock l -> + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), true) + ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) | _ -> () end; - event ctx e octx (* delegate to must lockset analysis *) + ctx.local let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let module Cfg = (val !MyCFG.current_cfg) in - let (lockset, multithread) = ctx.global g in - let next_lockset = - match Cfg.next g with - | [] -> lockset (* HACK for return nodes *) - | nexts -> - List.fold_left (fun acc (_, next_node) -> - let (locked, _) = ctx.global next_node in - D.join acc locked - ) (D.bot ()) nexts - in - let unlocked = D.diff lockset next_lockset in - let locked = D.diff next_lockset lockset in + let (locked, unlocked, multithread) = ctx.global g in let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> @@ -93,7 +62,7 @@ struct ) locked entries in let entries = - Locked.fold (fun l acc -> + Unlocked.fold (fun l acc -> let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in Queries.YS.add entry acc ) unlocked entries From c472adff1fdf72a6da6142d07f55e59069f91aeb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 18 Apr 2024 18:00:05 +0300 Subject: [PATCH 036/103] Add lock global unknowns to mutexGhosts --- src/analyses/mutexGhosts.ml | 92 +++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 0b11355d57..d80291532f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,8 +10,12 @@ struct module V = struct - include Node - let is_write_only _ = true + include Printable.Either (Node) (LockDomain.Addr) + let node x = `Left x + let lock x = `Right x + let is_write_only = function + | `Left _ -> false + | `Right _ -> true end module Locked = @@ -29,16 +33,29 @@ struct include BoolDomain.MayBool let name () = "multithread" end - module G = Lattice.Prod3 (Locked) (Unlocked) (MultiThread) + module G = + struct + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Unit) + let node = function + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) + | `Lifted1 x -> x + | _ -> failwith "MutexGhosts.node" + let lock = function + | `Bot -> Lattice.Unit.bot () + | `Lifted2 x -> x + | _ -> failwith "MutexGhosts.lock" + let create_node node = `Lifted1 node + let create_lock lock = `Lifted2 lock + end let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg ctx.prev_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ()) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())) | Events.Unlock l -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ()) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())) | Events.EnterMultiThreaded -> - ctx.sideg ctx.prev_node (Locked.bot (), Unlocked.bot (), true) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () end; ctx.local @@ -47,36 +64,41 @@ struct match q with | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in - let (locked, unlocked, multithread) = ctx.global g in - let entries = - (* TODO: do variable_entry-s only once *) - Locked.fold (fun l acc -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc - ) (Locked.union locked unlocked) (Queries.YS.empty ()) - in - let entries = - Locked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc - ) locked entries - in - let entries = - Unlocked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc - ) unlocked entries - in - let entries = - if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) - ) - else + begin match g with + | `Left g' -> + let (locked, unlocked, multithread) = G.node (ctx.global g) in + let g = g' in + let entries = + (* TODO: do variable_entry-s only once *) + Locked.fold (fun l acc -> + let entry = WitnessGhost.variable_entry ~task (Locked l) in + Queries.YS.add entry acc + ) (Locked.union locked unlocked) (Queries.YS.empty ()) + in + let entries = + Locked.fold (fun l acc -> + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in + Queries.YS.add entry acc + ) locked entries + in + let entries = + Unlocked.fold (fun l acc -> + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in + Queries.YS.add entry acc + ) unlocked entries + in + let entries = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries + in entries - in - entries + | `Right _ -> assert false + end | _ -> Queries.Result.top q end From fd64898163e98115a3d3dfd253856005796c68a9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:34:37 +0300 Subject: [PATCH 037/103] Add PARAM to 56-witness/64-ghost-multiple-protecting --- tests/regression/56-witness/64-ghost-multiple-protecting.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 012318ac49..589aa92bff 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,6 +1,6 @@ +// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType #include #include - int g1, g2; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; From e3ded4e20de4790baf9d9bf5b6fad2904d3ae598 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:34:55 +0300 Subject: [PATCH 038/103] Find ambiguous mutexes in mutexGhosts --- src/analyses/mutexGhosts.ml | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index d80291532f..083763f41b 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -35,7 +35,7 @@ struct end module G = struct - include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Unit) + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (BoolDomain.MayBool) let node = function | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) | `Lifted1 x -> x @@ -51,9 +51,25 @@ struct let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); + if !AnalysisState.postsolving then ( + let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + if Locked.cardinal locked > 1 then ( + Locked.iter (fun lock -> + ctx.sideg (V.lock lock) (G.create_lock true) + ) locked + ); + ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); + if !AnalysisState.postsolving then ( + let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in + if Locked.cardinal unlocked > 1 then ( + Locked.iter (fun lock -> + ctx.sideg (V.lock lock) (G.create_lock true) + ) unlocked + ); + ) | Events.EnterMultiThreaded -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () @@ -97,7 +113,7 @@ struct entries in entries - | `Right _ -> assert false + | `Right _ -> Queries.Result.top q end | _ -> Queries.Result.top q end From b96f8a210c18fa6f1380f29d90fe53f7ad77efbe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:50:04 +0300 Subject: [PATCH 039/103] Avoid emitting witness ghosts for ambiguous mutexes --- src/analyses/base.ml | 5 +- src/analyses/basePriv.ml | 10 +- src/analyses/mutexGhosts.ml | 42 ++++-- src/domains/queries.ml | 7 + src/witness/witnessGhost.ml | 4 +- .../56-witness/65-ghost-ambiguous-lock.t | 130 +----------------- 6 files changed, 55 insertions(+), 143 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 4cc5c51262..ac31e29163 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1248,7 +1248,10 @@ struct inv else ( let var = WitnessGhost.to_varinfo Multithreaded in - Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ctx.ask (GhostVarAvailable var) then + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none ) | `Right _ -> (* thread return *) Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 832aaf54c1..129d0d5d69 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -343,7 +343,10 @@ struct ) cpa Invariant.none in let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ask.f (GhostVarAvailable var) then + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none | g -> (* global *) invariant_global ask getg g @@ -859,7 +862,10 @@ struct let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> let var = WitnessGhost.to_varinfo (Locked m) in - Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if ask.f (GhostVarAvailable var) then + Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + else + Invariant.none ) locks inv ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 083763f41b..21a12db7a1 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -41,7 +41,7 @@ struct | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function - | `Bot -> Lattice.Unit.bot () + | `Bot -> BoolDomain.MayBool.bot () | `Lifted2 x -> x | _ -> failwith "MutexGhosts.lock" let create_node node = `Lifted1 node @@ -76,8 +76,14 @@ struct end; ctx.local + let ghost_var_available ctx = function + | WitnessGhost.Var.Locked lock -> not (G.lock (ctx.global (V.lock lock)): bool) + | Multithreaded -> true + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with + | GhostVarAvailable vi -> + GobOption.exists (ghost_var_available ctx) (WitnessGhost.from_varinfo vi) | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with @@ -87,27 +93,43 @@ struct let entries = (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.variable_entry ~task (Locked l) in + Queries.YS.add entry acc + ) + else + acc ) (Locked.union locked unlocked) (Queries.YS.empty ()) in let entries = Locked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in + Queries.YS.add entry acc + ) + else + acc ) locked entries in let entries = Unlocked.fold (fun l acc -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc + if ghost_var_available ctx (Locked l) then ( + let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in + Queries.YS.add entry acc + ) + else + acc ) unlocked entries in let entries = if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) + if ghost_var_available ctx Multithreaded then ( + let entry = WitnessGhost.variable_entry ~task Multithreaded in + let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in + Queries.YS.add entry (Queries.YS.add entry' entries) + ) + else + entries ) else entries diff --git a/src/domains/queries.ml b/src/domains/queries.ml index b9b13a7584..9a50af1907 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -130,6 +130,7 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t + | GhostVarAvailable: varinfo -> MustBool.t t type 'a result = 'a @@ -202,6 +203,7 @@ struct | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) + | GhostVarAvailable _ -> (module MustBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -273,6 +275,7 @@ struct | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () + | GhostVarAvailable _ -> MustBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -341,6 +344,7 @@ struct | Any (MaySignedOverflow _) -> 58 | Any (YamlEntryGlobal _) -> 59 | Any (MustProtectingLocks _) -> 60 + | Any (GhostVarAvailable _) -> 61 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -397,6 +401,7 @@ struct | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 | Any (MaySignedOverflow e1), Any (MaySignedOverflow e2) -> CilType.Exp.compare e1 e2 + | Any (GhostVarAvailable vi1), Any (GhostVarAvailable vi2) -> CilType.Varinfo.compare vi1 vi2 (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) @@ -441,6 +446,7 @@ struct | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv | Any (MaySignedOverflow e) -> CilType.Exp.hash e + | Any (GhostVarAvailable vi) -> CilType.Varinfo.hash vi (* IterSysVars: *) (* - argument is a function and functions cannot be compared in any meaningful way. *) (* - doesn't matter because IterSysVars is always queried from outside of the analysis, so MCP's query caching is not done for it. *) @@ -506,6 +512,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e + | Any (GhostVarAvailable vi) -> Pretty.dprintf "GhostVarAvailable %a" CilType.Varinfo.pretty vi end let to_value_domain_ask (ask: ask) = diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 2aca886e78..010f450954 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -19,6 +19,8 @@ struct | Locked _ -> assert false | Multithreaded -> "multithreaded" + let describe_varinfo _ _ = "" + let typ = function | Locked _ -> GoblintCil.intType | Multithreaded -> GoblintCil.intType @@ -30,7 +32,7 @@ end include Var -module Map = RichVarinfo.Make (Var) +module Map = RichVarinfo.BiVarinfoMap.Make (Var) include Map diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index ee586bd531..708e27ca64 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -4,7 +4,7 @@ dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 20 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -21,139 +21,11 @@ line: 29 column: 3 function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || g2 == 0)' - type: assertion - format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m1_locked || g1 == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' From c6f12a60491f6650fcb07ba01dd54344a4a30fe3 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:57:06 +0300 Subject: [PATCH 040/103] Move LockDomain.Symbolic to SymbLocksDomain --- src/analyses/symbLocks.ml | 4 +-- src/cdomains/lockDomain.ml | 50 -------------------------------- src/cdomains/symbLocksDomain.ml | 51 +++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/analyses/symbLocks.ml b/src/analyses/symbLocks.ml index 6fd18de6ff..b1727ace81 100644 --- a/src/analyses/symbLocks.ml +++ b/src/analyses/symbLocks.ml @@ -23,8 +23,8 @@ struct exception Top - module D = LockDomain.Symbolic - module C = LockDomain.Symbolic + module D = SymbLocksDomain.Symbolic + module C = SymbLocksDomain.Symbolic let name () = "symb_locks" diff --git a/src/cdomains/lockDomain.ml b/src/cdomains/lockDomain.ml index b22931001b..5aaa441428 100644 --- a/src/cdomains/lockDomain.ml +++ b/src/cdomains/lockDomain.ml @@ -74,53 +74,3 @@ module MayLocksetNoRW = struct include PreValueDomain.AD end - -module Symbolic = -struct - (* TODO: use SetDomain.Reverse *) - module S = SetDomain.ToppedSet (Exp) (struct let topname = "All mutexes" end) - include Lattice.Reverse (S) - - let rec eq_set (ask: Queries.ask) e = - S.union - (match ask.f (Queries.EqualSet e) with - | es when not (Queries.ES.is_bot es) -> - Queries.ES.fold S.add es (S.empty ()) - | _ -> S.empty ()) - (match e with - | SizeOf _ - | SizeOfE _ - | SizeOfStr _ - | AlignOf _ - | Const _ - | AlignOfE _ - | UnOp _ - | BinOp _ - | Question _ - | Real _ - | Imag _ - | AddrOfLabel _ -> S.empty () - | AddrOf (Var _,_) - | StartOf (Var _,_) - | Lval (Var _,_) -> S.singleton e - | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) - | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) - | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) - | CastE (_,e) -> eq_set ask e - ) - - let add (ask: Queries.ask) e st = - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.union addrs st - let remove ask e st = - (* TODO: Removing based on must-equality sets is not sound! *) - let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in - let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in - S.diff st addrs - let remove_var v st = S.filter (fun x -> not (SymbLocksDomain.Exp.contains_var v x)) st - - let filter = S.filter - let fold = S.fold - -end diff --git a/src/cdomains/symbLocksDomain.ml b/src/cdomains/symbLocksDomain.ml index ba2b96e8d0..bb260ad412 100644 --- a/src/cdomains/symbLocksDomain.ml +++ b/src/cdomains/symbLocksDomain.ml @@ -317,3 +317,54 @@ struct let of_mval (v, o) = of_mval (v, conv_const_offset o) end + + +module Symbolic = +struct + (* TODO: use SetDomain.Reverse *) + module S = SetDomain.ToppedSet (Exp) (struct let topname = "All mutexes" end) + include Lattice.Reverse (S) + + let rec eq_set (ask: Queries.ask) e = + S.union + (match ask.f (Queries.EqualSet e) with + | es when not (Queries.ES.is_bot es) -> + Queries.ES.fold S.add es (S.empty ()) + | _ -> S.empty ()) + (match e with + | SizeOf _ + | SizeOfE _ + | SizeOfStr _ + | AlignOf _ + | Const _ + | AlignOfE _ + | UnOp _ + | BinOp _ + | Question _ + | Real _ + | Imag _ + | AddrOfLabel _ -> S.empty () + | AddrOf (Var _,_) + | StartOf (Var _,_) + | Lval (Var _,_) -> S.singleton e + | AddrOf (Mem e,ofs) -> S.map (fun e -> AddrOf (Mem e,ofs)) (eq_set ask e) + | StartOf (Mem e,ofs) -> S.map (fun e -> StartOf (Mem e,ofs)) (eq_set ask e) + | Lval (Mem e,ofs) -> S.map (fun e -> Lval (Mem e,ofs)) (eq_set ask e) + | CastE (_,e) -> eq_set ask e + ) + + let add (ask: Queries.ask) e st = + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.union addrs st + let remove ask e st = + (* TODO: Removing based on must-equality sets is not sound! *) + let no_casts = S.map Expcompare.stripCastsDeepForPtrArith (eq_set ask e) in + let addrs = S.filter (function AddrOf _ -> true | _ -> false) no_casts in + S.diff st addrs + let remove_var v st = S.filter (fun x -> not (Exp.contains_var v x)) st + + let filter = S.filter + let fold = S.fold + +end From 8985d64633a0b3d0f6812df8ee784c87f332f499 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:57:37 +0300 Subject: [PATCH 041/103] Extract WitnessGhostVar to break dependency cycle --- src/witness/witnessGhost.ml | 30 +---------------------------- src/witness/witnessGhostVar.ml | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 29 deletions(-) create mode 100644 src/witness/witnessGhostVar.ml diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 010f450954..cdd26b36aa 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,34 +1,6 @@ (** Ghost variables for YAML witnesses. *) -module Var = -struct - type t = - | Locked of LockDomain.Addr.t - | Multithreaded - [@@deriving eq, hash] - - let name_varinfo = function - | Locked (Addr (v, _) as l) -> - let name = - if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then - Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) - else - LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) - in - name ^ "_locked" - | Locked _ -> assert false - | Multithreaded -> "multithreaded" - - let describe_varinfo _ _ = "" - - let typ = function - | Locked _ -> GoblintCil.intType - | Multithreaded -> GoblintCil.intType - - let initial = function - | Locked _ -> GoblintCil.zero - | Multithreaded -> GoblintCil.zero -end +module Var = WitnessGhostVar include Var diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml new file mode 100644 index 0000000000..afcf5d4dba --- /dev/null +++ b/src/witness/witnessGhostVar.ml @@ -0,0 +1,35 @@ +(** Ghost variables for YAML witnesses. *) + +type t = + | Locked of LockDomain.Addr.t + | Multithreaded +[@@deriving eq, ord, hash] + +let name_varinfo = function + | Locked (Addr (v, _) as l) -> + let name = + if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then + Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) + else + LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + in + name ^ "_locked" + | Locked _ -> assert false + | Multithreaded -> "multithreaded" + +let show = name_varinfo + +include Printable.SimpleShow (struct + type nonrec t = t + let show = show + end) + +let describe_varinfo _ _ = "" + +let typ = function + | Locked _ -> GoblintCil.intType + | Multithreaded -> GoblintCil.intType + +let initial = function + | Locked _ -> GoblintCil.zero + | Multithreaded -> GoblintCil.zero From b04af51f2d86bb20d7908a72948fd97275fdce14 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 13:58:55 +0300 Subject: [PATCH 042/103] Refactor GhostVarAvailable query --- src/analyses/base.ml | 5 +++-- src/analyses/basePriv.ml | 10 ++++++---- src/analyses/mutexGhosts.ml | 3 +-- src/domains/queries.ml | 12 ++++++------ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index ac31e29163..c1001f8b80 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,9 +1247,10 @@ struct if get_bool "exp.earlyglobs" then inv else ( - let var = WitnessGhost.to_varinfo Multithreaded in - if ctx.ask (GhostVarAvailable var) then + if ctx.ask (GhostVarAvailable Multithreaded) then ( + let var = WitnessGhost.to_varinfo Multithreaded in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none ) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 129d0d5d69..7a667c9c43 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -342,9 +342,10 @@ struct acc ) cpa Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - if ask.f (GhostVarAvailable var) then + if ask.f (GhostVarAvailable (Locked m')) then ( + let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none | g -> (* global *) @@ -861,9 +862,10 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - let var = WitnessGhost.to_varinfo (Locked m) in - if ask.f (GhostVarAvailable var) then + if ask.f (GhostVarAvailable (Locked m)) then ( + let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) else Invariant.none ) locks inv diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 21a12db7a1..5ffdac6110 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -82,8 +82,7 @@ struct let query ctx (type a) (q: a Queries.t): a Queries.result = match q with - | GhostVarAvailable vi -> - GobOption.exists (ghost_var_available ctx) (WitnessGhost.from_varinfo vi) + | GhostVarAvailable v -> ghost_var_available ctx v | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 9a50af1907..44a0402a93 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -130,7 +130,7 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t - | GhostVarAvailable: varinfo -> MustBool.t t + | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t type 'a result = 'a @@ -203,7 +203,7 @@ struct | TmpSpecial _ -> (module ML) | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) - | GhostVarAvailable _ -> (module MustBool) + | GhostVarAvailable _ -> (module MayBool) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -275,7 +275,7 @@ struct | TmpSpecial _ -> ML.top () | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () - | GhostVarAvailable _ -> MustBool.top () + | GhostVarAvailable _ -> MayBool.top () end (* The type any_query can't be directly defined in Any as t, @@ -401,7 +401,7 @@ struct | Any (MustBeSingleThreaded {since_start=s1;}), Any (MustBeSingleThreaded {since_start=s2;}) -> Stdlib.compare s1 s2 | Any (TmpSpecial lv1), Any (TmpSpecial lv2) -> Mval.Exp.compare lv1 lv2 | Any (MaySignedOverflow e1), Any (MaySignedOverflow e2) -> CilType.Exp.compare e1 e2 - | Any (GhostVarAvailable vi1), Any (GhostVarAvailable vi2) -> CilType.Varinfo.compare vi1 vi2 + | Any (GhostVarAvailable v1), Any (GhostVarAvailable v2) -> WitnessGhostVar.compare v1 v2 (* only argumentless queries should remain *) | _, _ -> Stdlib.compare (order a) (order b) @@ -446,7 +446,7 @@ struct | Any (MustBeSingleThreaded {since_start}) -> Hashtbl.hash since_start | Any (TmpSpecial lv) -> Mval.Exp.hash lv | Any (MaySignedOverflow e) -> CilType.Exp.hash e - | Any (GhostVarAvailable vi) -> CilType.Varinfo.hash vi + | Any (GhostVarAvailable v) -> WitnessGhostVar.hash v (* IterSysVars: *) (* - argument is a function and functions cannot be compared in any meaningful way. *) (* - doesn't matter because IterSysVars is always queried from outside of the analysis, so MCP's query caching is not done for it. *) @@ -512,7 +512,7 @@ struct | Any IsEverMultiThreaded -> Pretty.dprintf "IsEverMultiThreaded" | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e - | Any (GhostVarAvailable vi) -> Pretty.dprintf "GhostVarAvailable %a" CilType.Varinfo.pretty vi + | Any (GhostVarAvailable v) -> Pretty.dprintf "GhostVarAvailable %a" WitnessGhostVar.pretty v end let to_value_domain_ask (ask: ask) = From d8bd13d7a6770e75fc14958a69510b964bdc4937 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 19 Apr 2024 16:23:05 +0300 Subject: [PATCH 043/103] Exclude WitnessGhostVar from docs check --- scripts/goblint-lib-modules.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/goblint-lib-modules.py b/scripts/goblint-lib-modules.py index 017530f838..98b8acd39f 100755 --- a/scripts/goblint-lib-modules.py +++ b/scripts/goblint-lib-modules.py @@ -44,6 +44,7 @@ "MessageCategory", # included in Messages "PreValueDomain", # included in ValueDomain + "WitnessGhostVar", # included in WitnessGhost "ConfigVersion", "ConfigProfile", From 947d6bc4382c36778c5f6de2d07b07be9637a7ab Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 12:51:14 +0300 Subject: [PATCH 044/103] Fix __VERIFIER_atomic special mutex ghost varialbe name --- src/witness/witnessGhostVar.ml | 5 +- tests/regression/29-svcomp/16-atomic_priv.t | 88 +++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/regression/29-svcomp/16-atomic_priv.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index afcf5d4dba..bc0f98f915 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -8,10 +8,13 @@ type t = let name_varinfo = function | Locked (Addr (v, _) as l) -> let name = + if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then + "__VERIFIER_atomic" + else if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) else - LockDomain.Addr.show l (* TODO: valid names with interval offsets, etc *) + LockDomain.Addr.show l (* TODO: valid names with fields, interval offsets, etc *) in name ^ "_locked" | Locked _ -> assert false diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t new file mode 100644 index 0000000000..98584b96d0 --- /dev/null +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -0,0 +1,88 @@ + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) + [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:24:3-24:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:26:3-26:33) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 17 + dead: 0 + total lines: 17 + [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: __VERIFIER_atomic_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || myglobal == 5' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + type: assertion + format: C From 4ada6eb2ced86b2021bde12937a237d716b6daa4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 12:55:56 +0300 Subject: [PATCH 045/103] Avoid emitting useless protected invariants from protection privatization --- src/analyses/basePriv.ml | 2 ++ tests/regression/29-svcomp/16-atomic_priv.t | 7 +------ tests/regression/56-witness/64-ghost-multiple-protecting.t | 7 +------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7a667c9c43..7cadf637ad 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -859,6 +859,8 @@ struct let locks = ask.f (Q.MustProtectingLocks g') in if Q.AD.is_top locks || Q.AD.is_empty locks then Invariant.none + else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then + Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 98584b96d0..15425f68dd 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 8 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -81,8 +81,3 @@ string: '! multithreaded || myglobal == 5' type: assertion format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' - type: assertion - format: C diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index d51db2285e..53323355c5 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -4,7 +4,7 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 17 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -133,11 +133,6 @@ protection doesn't have precise protected invariant for g2. string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' type: assertion format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || (m1_locked || (0 <= g2 && g2 <= 1)))' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' From a7d43a938181ca404666147d2fc705c09a0fa8e4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 13:04:26 +0300 Subject: [PATCH 046/103] Avoid useless work in mutex-meet invariant_global if ghost variable isn't available --- src/analyses/basePriv.ml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7cadf637ad..799290c4fe 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -333,16 +333,16 @@ struct let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) - let cpa = getg m in - let inv = CPA.fold (fun v _ acc -> - if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then - let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in - Invariant.(acc && inv) - else - acc - ) cpa Invariant.none - in if ask.f (GhostVarAvailable (Locked m')) then ( + let cpa = getg m in + let inv = CPA.fold (fun v _ acc -> + if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then + let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in + Invariant.(acc && inv) + else + acc + ) cpa Invariant.none + in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) From d6abc0b4f14dccbd1c500ce3a9e23f72497aa966 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 13:44:29 +0300 Subject: [PATCH 047/103] Fix struct field mutex ghost variable name --- src/witness/witnessGhostVar.ml | 11 ++- tests/regression/13-privatized/25-struct_nr.t | 83 +++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) create mode 100644 tests/regression/13-privatized/25-struct_nr.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index bc0f98f915..cac48050de 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -6,7 +6,7 @@ type t = [@@deriving eq, ord, hash] let name_varinfo = function - | Locked (Addr (v, _) as l) -> + | Locked (Addr (v, os)) -> let name = if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then "__VERIFIER_atomic" @@ -14,9 +14,14 @@ let name_varinfo = function if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) else - LockDomain.Addr.show l (* TODO: valid names with fields, interval offsets, etc *) + Basetype.Variables.show v in - name ^ "_locked" + let rec offs: LockDomain.Addr.Offs.t -> string = function + | `NoOffset -> "" + | `Field (f, os') -> "_" ^ f.fname ^ offs os' + | `Index (i, os') -> failwith "TODO" (* TODO: valid names with interval offsets, etc *) + in + name ^ offs os ^ "_locked" | Locked _ -> assert false | Multithreaded -> "multithreaded" diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t new file mode 100644 index 0000000000..f3ebcd1c52 --- /dev/null +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -0,0 +1,83 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 25-struct_nr.c + [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) + [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) + [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) + [Success][Assert] Assertion "glob1 == 6" will succeed (25-struct_nr.c:30:3-30:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 19 + dead: 0 + total lines: 19 + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "1" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "0" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + - entry_type: ghost_update + variable: lock1_mutex_locked + expression: "0" + location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: lock1_mutex_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (lock1_mutex_locked || glob1 == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((-128 <= glob1 && glob1 <= 127) && glob1 != 0)' + type: assertion + format: C From 6db1d04eeb551a5726bb373e7cc6e6e0394a4368 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 14:34:05 +0300 Subject: [PATCH 048/103] Fix definite array index mutex ghost variable name --- src/witness/witnessGhostVar.ml | 5 +- tests/regression/13-privatized/80-idx_priv.c | 26 +++++++ tests/regression/13-privatized/80-idx_priv.t | 80 ++++++++++++++++++++ 3 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 tests/regression/13-privatized/80-idx_priv.c create mode 100644 tests/regression/13-privatized/80-idx_priv.t diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index cac48050de..cec61b0e2d 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -19,7 +19,10 @@ let name_varinfo = function let rec offs: LockDomain.Addr.Offs.t -> string = function | `NoOffset -> "" | `Field (f, os') -> "_" ^ f.fname ^ offs os' - | `Index (i, os') -> failwith "TODO" (* TODO: valid names with interval offsets, etc *) + | `Index (i, os') -> + match ValueDomain.ID.to_int i with + | Some i -> assert Z.Compare.(i >= Z.zero); "_" ^ Z.to_string i + | _ -> assert false (* must locksets cannot have ambiguous indices *) in name ^ offs os ^ "_locked" | Locked _ -> assert false diff --git a/tests/regression/13-privatized/80-idx_priv.c b/tests/regression/13-privatized/80-idx_priv.c new file mode 100644 index 0000000000..ed0e8d3228 --- /dev/null +++ b/tests/regression/13-privatized/80-idx_priv.c @@ -0,0 +1,26 @@ +#include +#include + +int data; +pthread_mutex_t m[10]; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[4]); + data++; // NORACE + data--; // NORACE + pthread_mutex_unlock(&m[4]); + return NULL; +} + +int main() { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&m[i], NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&m[4]); + __goblint_check(data == 0); // NORACE + pthread_mutex_unlock(&m[4]); + return 0; +} + diff --git a/tests/regression/13-privatized/80-idx_priv.t b/tests/regression/13-privatized/80-idx_priv.t new file mode 100644 index 0000000000..698744924c --- /dev/null +++ b/tests/regression/13-privatized/80-idx_priv.t @@ -0,0 +1,80 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 80-idx_priv.c + [Success][Assert] Assertion "data == 0" will succeed (80-idx_priv.c:22:3-22:29) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 0 + total lines: 14 + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 80-idx_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_4_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_4_locked || data == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= data && data <= 1)' + type: assertion + format: C From 53a714fe979757f8f71c1ea408f3a3e5ccd4120c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 15:28:26 +0300 Subject: [PATCH 049/103] Make non-definite ghost variables unavailable --- src/analyses/mutexGhosts.ml | 2 +- .../56-witness/68-ghost-ambiguous-idx.c | 28 +++++++ .../56-witness/68-ghost-ambiguous-idx.t | 78 +++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/regression/56-witness/68-ghost-ambiguous-idx.c create mode 100644 tests/regression/56-witness/68-ghost-ambiguous-idx.t diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 5ffdac6110..128355e919 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -77,7 +77,7 @@ struct ctx.local let ghost_var_available ctx = function - | WitnessGhost.Var.Locked lock -> not (G.lock (ctx.global (V.lock lock)): bool) + | WitnessGhost.Var.Locked lock -> LockDomain.Addr.is_definite lock && not (G.lock (ctx.global (V.lock lock))) | Multithreaded -> true let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.c b/tests/regression/56-witness/68-ghost-ambiguous-idx.c new file mode 100644 index 0000000000..7babbe003c --- /dev/null +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.c @@ -0,0 +1,28 @@ +#include +#include + +int data; +pthread_mutex_t m[10]; + +void *t_fun(void *arg) { + pthread_mutex_lock(&m[4]); + data++; + data--; + pthread_mutex_unlock(&m[4]); + return NULL; +} + +int main() { + for (int i = 0; i < 10; i++) + pthread_mutex_init(&m[i], NULL); + + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + int r; + int j = r ? 4 : 5; + pthread_mutex_lock(&m[r]); + __goblint_check(data == 0); // UNKNOWN! + pthread_mutex_unlock(&m[4]); + return 0; +} + diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t new file mode 100644 index 0000000000..0f6191188e --- /dev/null +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -0,0 +1,78 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 68-ghost-ambiguous-idx.c + [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) + [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 0 + total lines: 15 + [Warning][Race] Memory location data (race with conf. 110): (68-ghost-ambiguous-idx.c:4:5-4:9) + write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:9:3-9:9) + write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) + read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) + [Info][Witness] witness generation summary: + total generation entries: 8 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "1" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: m_4_locked + expression: "0" + location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m_4_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_4_locked || data == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= data && data <= 1)' + type: assertion + format: C + +TODO: there shouldn't be invariant with m_4_locked because it's ambiguously used From 413b2e17dd3e4e8b7e53ec50af475eee539d44ee Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 23 Apr 2024 15:32:59 +0300 Subject: [PATCH 050/103] Disable mutex ghosts with indices --- src/analyses/mutexGhosts.ml | 3 +- tests/regression/13-privatized/80-idx_priv.t | 50 ++----------------- .../56-witness/68-ghost-ambiguous-idx.t | 41 +-------------- 3 files changed, 6 insertions(+), 88 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 128355e919..b7001c6c2f 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -77,7 +77,8 @@ struct ctx.local let ghost_var_available ctx = function - | WitnessGhost.Var.Locked lock -> LockDomain.Addr.is_definite lock && not (G.lock (ctx.global (V.lock lock))) + | WitnessGhost.Var.Locked (Addr (v, o) as lock) -> not (LockDomain.Offs.contains_index o) && not (G.lock (ctx.global (V.lock lock))) + | Locked _ -> false | Multithreaded -> true let query ctx (type a) (q: a Queries.t): a Queries.result = diff --git a/tests/regression/13-privatized/80-idx_priv.t b/tests/regression/13-privatized/80-idx_priv.t index 698744924c..bf15cfb538 100644 --- a/tests/regression/13-privatized/80-idx_priv.t +++ b/tests/regression/13-privatized/80-idx_priv.t @@ -5,7 +5,7 @@ dead: 0 total lines: 14 [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -22,59 +22,15 @@ line: 20 column: 3 function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 80-idx_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m_4_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_4_locked || data == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' type: assertion format: C + +TODO: protected invariant with m_4_locked without making 56-witness/68-ghost-ambiguous-idx unsound diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 0f6191188e..48837fcabb 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -10,7 +10,7 @@ write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -27,52 +27,13 @@ line: 20 column: 3 function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "1" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: m_4_locked - expression: "0" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: m_4_locked - scope: global - type: int - initial: "0" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_4_locked || data == 0)' - type: assertion - format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' type: assertion format: C - -TODO: there shouldn't be invariant with m_4_locked because it's ambiguously used From ea849fbb840452090517c6395c78fbffd5226ea4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 10:28:28 +0300 Subject: [PATCH 051/103] Detect thread create nodes in mutexGhosts --- src/analyses/mutexGhosts.ml | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index b7001c6c2f..803f80f3e6 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -33,11 +33,16 @@ struct include BoolDomain.MayBool let name () = "multithread" end + module ThreadCreate = + struct + include BoolDomain.MayBool + let name () = "threadcreate" + end module G = struct - include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (BoolDomain.MayBool) + include Lattice.Lift2 (Lattice.Prod4 (Locked) (Unlocked) (MultiThread) (ThreadCreate)) (BoolDomain.MayBool) let node = function - | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ()) | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function @@ -51,9 +56,9 @@ struct let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ())); if !AnalysisState.postsolving then ( - let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (locked, _, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -61,9 +66,9 @@ struct ); ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot (), ThreadCreate.bot ())); if !AnalysisState.postsolving then ( - let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (_, unlocked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -71,11 +76,15 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true, ThreadCreate.bot ())) | _ -> () end; ctx.local + let threadspawn ctx ~multiple lval f args octx = + ctx.sideg (V.node ctx.node) (G.create_node (Locked.bot (), Unlocked.bot (), MultiThread.bot (), true)); + ctx.local + let ghost_var_available ctx = function | WitnessGhost.Var.Locked (Addr (v, o) as lock) -> not (LockDomain.Offs.contains_index o) && not (G.lock (ctx.global (V.lock lock))) | Locked _ -> false @@ -88,7 +97,7 @@ struct let g: V.t = Obj.obj g in begin match g with | `Left g' -> - let (locked, unlocked, multithread) = G.node (ctx.global g) in + let (locked, unlocked, multithread, threadcreate) = G.node (ctx.global g) in let g = g' in let entries = (* TODO: do variable_entry-s only once *) From 594beaceed70cb0e85ed0b56c9c26711becc1956 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 10:44:00 +0300 Subject: [PATCH 052/103] Refactor mutexGhosts thread creation collection --- src/analyses/mutexGhosts.ml | 44 +++++++++++++++++++++---------------- src/domains/queries.ml | 1 + 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 803f80f3e6..9ddde5d37e 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -2,20 +2,25 @@ open Analyses +module NodeSet = Queries.NS + module Spec = struct include UnitAnalysis.Spec let name () = "mutexGhosts" + module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) module V = struct - include Printable.Either (Node) (LockDomain.Addr) + include Printable.Either3 (Node) (LockDomain.Addr) (ThreadCreate) let node x = `Left x - let lock x = `Right x + let lock x = `Middle x + let threadcreate = `Right () let is_write_only = function | `Left _ -> false - | `Right _ -> true + | `Middle _ -> true + | `Right _ -> false end module Locked = @@ -33,32 +38,32 @@ struct include BoolDomain.MayBool let name () = "multithread" end - module ThreadCreate = - struct - include BoolDomain.MayBool - let name () = "threadcreate" - end module G = struct - include Lattice.Lift2 (Lattice.Prod4 (Locked) (Unlocked) (MultiThread) (ThreadCreate)) (BoolDomain.MayBool) + include Lattice.Lift2 (Lattice.Prod3 (Locked) (Unlocked) (MultiThread)) (Lattice.Lift2 (BoolDomain.MayBool) (NodeSet)) let node = function - | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ()) + | `Bot -> (Locked.bot (), Unlocked.bot (), MultiThread.bot ()) | `Lifted1 x -> x | _ -> failwith "MutexGhosts.node" let lock = function | `Bot -> BoolDomain.MayBool.bot () - | `Lifted2 x -> x + | `Lifted2 (`Lifted1 x) -> x | _ -> failwith "MutexGhosts.lock" + let threadcreate = function + | `Bot -> NodeSet.bot () + | `Lifted2 (`Lifted2 x) -> x + | _ -> failwith "MutexGhosts.threadcreate" let create_node node = `Lifted1 node - let create_lock lock = `Lifted2 lock + let create_lock lock = `Lifted2 (`Lifted1 lock) + let create_threadcreate threadcreate = `Lifted2 (`Lifted2 threadcreate) end let event ctx e octx = begin match e with | Events.Lock (l, _) -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot (), ThreadCreate.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( - let (locked, _, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -66,9 +71,9 @@ struct ); ) | Events.Unlock l -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot (), ThreadCreate.bot ())); + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( - let (_, unlocked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in + let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> ctx.sideg (V.lock lock) (G.create_lock true) @@ -76,13 +81,13 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true, ThreadCreate.bot ())) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) | _ -> () end; ctx.local let threadspawn ctx ~multiple lval f args octx = - ctx.sideg (V.node ctx.node) (G.create_node (Locked.bot (), Unlocked.bot (), MultiThread.bot (), true)); + ctx.sideg V.threadcreate (G.create_threadcreate (NodeSet.singleton ctx.node)); ctx.local let ghost_var_available ctx = function @@ -97,7 +102,7 @@ struct let g: V.t = Obj.obj g in begin match g with | `Left g' -> - let (locked, unlocked, multithread, threadcreate) = G.node (ctx.global g) in + let (locked, unlocked, multithread) = G.node (ctx.global g) in let g = g' in let entries = (* TODO: do variable_entry-s only once *) @@ -144,6 +149,7 @@ struct entries in entries + | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end | _ -> Queries.Result.top q diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 44a0402a93..515198854d 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -10,6 +10,7 @@ module LS = VDQ.LS module TS = SetDomain.ToppedSet (CilType.Typ) (struct let topname = "All" end) module ES = SetDomain.Reverse (SetDomain.ToppedSet (CilType.Exp) (struct let topname = "All" end)) module VS = SetDomain.ToppedSet (CilType.Varinfo) (struct let topname = "All" end) +module NS = SetDomain.ToppedSet (Node) (struct let topname = "All" end) module NFL = WrapperFunctionAnalysis0.NodeFlatLattice module TC = WrapperFunctionAnalysis0.ThreadCreateUniqueCount From 584b78842a0a38fee98c73d59629a707218b0e0a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 24 Apr 2024 11:06:39 +0300 Subject: [PATCH 053/103] Add option to emit flow_insensitive_invariant-s as location_invariant-s --- src/analyses/mutexGhosts.ml | 1 + src/config/options.schema.json | 6 +++ src/domains/queries.ml | 5 +++ src/witness/yamlWitness.ml | 21 ++++++++-- tests/regression/13-privatized/74-mutex.t | 50 ++++++++++++++++++++++- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 9ddde5d37e..75195e4662 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -152,6 +152,7 @@ struct | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end + | InvariantGlobalNodes -> (G.threadcreate (ctx.global V.threadcreate): NodeSet.t) | _ -> Queries.Result.top q end diff --git a/src/config/options.schema.json b/src/config/options.schema.json index db93e74ff4..3065325f4e 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2493,6 +2493,12 @@ "description": "Emit invariants with typedef-ed types (e.g. in casts). Our validator cannot parse these.", "type": "boolean", "default": true + }, + "flow_insensitive-as-location": { + "title": "witness.invariant.flow_insensitive-as-location", + "description": "Emit flow-insensitive invariants as location invariants at certain locations.", + "type": "boolean", + "default": false } }, "additionalProperties": false diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 515198854d..152fb5f1a5 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -132,6 +132,7 @@ type _ t = | MaySignedOverflow: exp -> MayBool.t t | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t + | InvariantGlobalNodes: NS.t t (* TODO: V.t argument? *) type 'a result = 'a @@ -205,6 +206,7 @@ struct | MaySignedOverflow _ -> (module MayBool) | YamlEntryGlobal _ -> (module YS) | GhostVarAvailable _ -> (module MayBool) + | InvariantGlobalNodes -> (module NS) (** Get bottom result for query. *) let bot (type a) (q: a t): a result = @@ -277,6 +279,7 @@ struct | MaySignedOverflow _ -> MayBool.top () | YamlEntryGlobal _ -> YS.top () | GhostVarAvailable _ -> MayBool.top () + | InvariantGlobalNodes -> NS.top () end (* The type any_query can't be directly defined in Any as t, @@ -346,6 +349,7 @@ struct | Any (YamlEntryGlobal _) -> 59 | Any (MustProtectingLocks _) -> 60 | Any (GhostVarAvailable _) -> 61 + | Any InvariantGlobalNodes -> 62 let rec compare a b = let r = Stdlib.compare (order a) (order b) in @@ -514,6 +518,7 @@ struct | Any (TmpSpecial lv) -> Pretty.dprintf "TmpSpecial %a" Mval.Exp.pretty lv | Any (MaySignedOverflow e) -> Pretty.dprintf "MaySignedOverflow %a" CilType.Exp.pretty e | Any (GhostVarAvailable v) -> Pretty.dprintf "GhostVarAvailable %a" WitnessGhostVar.pretty v + | Any InvariantGlobalNodes -> Pretty.dprintf "InvariantGlobalNodes" end let to_value_domain_ask (ask: ask) = diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 9eafae009f..49fe889c22 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -325,18 +325,33 @@ struct (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( + let ns = R.ask_global InvariantGlobalNodes in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) - begin match R.ask_global (InvariantGlobal (Obj.repr g)) with - | `Lifted inv -> + begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_bool "witness.invariant.flow_insensitive-as-location" with + | `Lifted inv, false -> let invs = WitnessUtil.InvariantExp.process_exp inv in List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.flow_insensitive_invariant ~task ~invariant in entry :: acc ) acc invs - | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) + | `Lifted inv, true -> + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + let loc = Node.location n in + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc invs + ) ns acc + | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end | `Right _ -> (* contexts global *) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 6f84aa184f..a00f49eb1a 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -15,7 +15,7 @@ unsafe: 0 total memory locations: 1 - $ yamlWitnessStrip < witness.yml + $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - entry_type: ghost_update variable: multithreaded expression: "1" @@ -82,6 +82,54 @@ type: assertion format: C +Flow-insensitive invariants as location invariants. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 1 + total lines: 16 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml > witness.location.yml + + $ diff witness.flow_insensitive.yml witness.location.yml + 56,57c56,63 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 74-mutex.c + > file_hash: $FILE_HASH + > line: 36 + > column: 3 + > function: main + > location_invariant: + 61,62c67,74 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 74-mutex.c + > file_hash: $FILE_HASH + > line: 36 + > column: 3 + > function: main + > location_invariant: + [1] + Should also work with earlyglobs. Earlyglobs shouldn't cause protected writes in multithreaded mode from being immediately published to protected invariant. From 8d5cc1275a71283c88cdd3136715da524cec7b51 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:13:39 +0300 Subject: [PATCH 054/103] Add svcomp-ghost conf --- conf/svcomp-ghost.json | 145 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 conf/svcomp-ghost.json diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json new file mode 100644 index 0000000000..62feb25993 --- /dev/null +++ b/conf/svcomp-ghost.json @@ -0,0 +1,145 @@ +{ + "ana": { + "sv-comp": { + "enabled": true, + "functions": true + }, + "int": { + "def_exc": true, + "enums": false, + "interval": true + }, + "float": { + "interval": true + }, + "activated": [ + "base", + "threadid", + "threadflag", + "threadreturn", + "mallocWrapper", + "mutexEvents", + "mutex", + "access", + "race", + "escape", + "expRelation", + "mhp", + "assert", + "var_eq", + "symb_locks", + "region", + "thread", + "threadJoins", + "mutexGhosts", + "pthreadMutexType" + ], + "path_sens": [ + "mutex", + "malloc_null", + "uninit", + "expsplit", + "activeSetjmp", + "memLeak", + "threadflag" + ], + "context": { + "widen": false + }, + "malloc": { + "wrappers": [ + "kmalloc", + "__kmalloc", + "usb_alloc_urb", + "__builtin_alloca", + "kzalloc", + + "ldv_malloc", + + "kzalloc_node", + "ldv_zalloc", + "kmalloc_array", + "kcalloc", + + "ldv_xmalloc", + "ldv_xzalloc", + "ldv_calloc", + "ldv_kzalloc" + ] + }, + "base": { + "arrays": { + "domain": "partitioned" + } + }, + "race": { + "free": false, + "call": false + }, + "autotune": { + "enabled": true, + "activated": [ + "singleThreaded", + "mallocWrappers", + "noRecursiveIntervals", + "enums", + "congruence", + "octagon", + "wideningThresholds", + "loopUnrollHeuristic", + "memsafetySpecification", + "termination", + "tmpSpecialAnalysis" + ] + } + }, + "exp": { + "region-offsets": true + }, + "solver": "td3", + "sem": { + "unknown_function": { + "spawn": false + }, + "int": { + "signed_overflow": "assume_none" + }, + "null-pointer": { + "dereference": "assume_none" + } + }, + "witness": { + "graphml": { + "enabled": false + }, + "yaml": { + "enabled": true, + "format-version": "2.0", + "entry-types": [ + "flow_insensitive_invariant" + ] + }, + "invariant": { + "loop-head": true, + "after-lock": true, + "other": true, + "accessed": true, + "exact": true, + "all-locals": false, + "flow_insensitive-as-location": true, + "exclude-vars": [ + "tmp\\(___[0-9]+\\)?", + "cond", + "RETURN", + "__\\(cil_\\)?tmp_?[0-9]*\\(_[0-9]+\\)?", + ".*____CPAchecker_TMP_[0-9]+", + "__VERIFIER_assert__cond", + "__ksymtab_.*", + "\\(ldv_state_variable\\|ldv_timer_state\\|ldv_timer_list\\|ldv_irq_\\(line_\\|data_\\)?[0-9]+\\|ldv_retval\\)_[0-9]+" + ] + } + }, + "pre": { + "enabled": false + } +} From 96d862e4369df5355f80fcc69a94c7e53de806ac Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:14:19 +0300 Subject: [PATCH 055/103] Use YAML witness format-version 0.1 for svcomp-ghost --- conf/svcomp-ghost.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 62feb25993..229dd9ef46 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -114,7 +114,7 @@ }, "yaml": { "enabled": true, - "format-version": "2.0", + "format-version": "0.1", "entry-types": [ "flow_insensitive_invariant" ] From 257fa8cd374f4b339427eb4c2c52cf67d72aa298 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:24:44 +0300 Subject: [PATCH 056/103] Test witness.invariant.flow_insensitive-as-location with for loop --- .../regression/13-privatized/04-priv_multi.t | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 tests/regression/13-privatized/04-priv_multi.t diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t new file mode 100644 index 0000000000..9bdf8ac5a7 --- /dev/null +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -0,0 +1,309 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 04-priv_multi.c + [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) + [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) + [Warning][Deadcode] Function 'dispose' has dead code: + on line 53 (04-priv_multi.c:53-53) + on line 56 (04-priv_multi.c:56-56) + [Warning][Deadcode] Function 'process' has dead code: + on line 37 (04-priv_multi.c:37-37) + on line 40 (04-priv_multi.c:40-40) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 40 + dead: 4 + total lines: 44 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:25:10-25:11) + [Warning][Deadcode][CWE-571] condition 'A > 0' is always true (04-priv_multi.c:27:9-27:14) + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) + [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) + [Info][Witness] witness generation summary: + total generation entries: 19 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 69 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 46 + column: 5 + function: dispose + - entry_type: ghost_update + variable: mutex_B_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 29 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 73 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 49 + column: 7 + function: dispose + - entry_type: ghost_update + variable: mutex_B_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 32 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 68 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 26 + column: 5 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 15 + column: 5 + function: generate + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 74 + column: 5 + function: main + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 34 + column: 7 + function: process + - entry_type: ghost_update + variable: mutex_A_locked + expression: "0" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 18 + column: 5 + function: generate + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 63 + column: 3 + function: main + - entry_type: ghost_variable + variable: mutex_B_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: mutex_A_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (mutex_A_locked || A == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + type: assertion + format: C + +Flow-insensitive invariants as location invariants. + + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) + [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) + [Warning][Deadcode] Function 'dispose' has dead code: + on line 53 (04-priv_multi.c:53-53) + on line 56 (04-priv_multi.c:56-56) + [Warning][Deadcode] Function 'process' has dead code: + on line 37 (04-priv_multi.c:37-37) + on line 40 (04-priv_multi.c:40-40) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 40 + dead: 4 + total lines: 44 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:25:10-25:11) + [Warning][Deadcode][CWE-571] condition 'A > 0' is always true (04-priv_multi.c:27:9-27:14) + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) + [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) + [Info][Witness] witness generation summary: + total generation entries: 25 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 0 + total memory locations: 2 + + $ yamlWitnessStrip < witness.yml > witness.location.yml + +Location invariant at `for` loop in `main` should be on column 3, not 7. + + $ diff witness.flow_insensitive.yml witness.location.yml + 133,134c133,140 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + 138,139c144,151 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + 143,144c155,228 + < - entry_type: flow_insensitive_invariant + < flow_insensitive_invariant: + --- + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 67 + > column: 7 + > function: main + > location_invariant: + > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_A_locked || A == 5)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 65 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + > string: '! multithreaded || (mutex_A_locked || A == 5)' + > type: assertion + > format: C + > - entry_type: location_invariant + > location: + > file_name: 04-priv_multi.c + > file_hash: $FILE_HASH + > line: 64 + > column: 3 + > function: main + > location_invariant: + [1] From 10dfba1437956105d7a5a91c3f3bf410ebbc9b36 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 25 Apr 2024 10:29:53 +0300 Subject: [PATCH 057/103] Fix witness.invariant.flow_insensitive-as-location at loop node --- src/witness/yamlWitness.ml | 18 ++++++++++-------- tests/regression/13-privatized/04-priv_multi.t | 6 +++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 49fe889c22..b7bf11a31c 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -342,14 +342,16 @@ struct let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> let fundec = Node.find_fundec n in - let loc = Node.location n in - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = Entry.invariant (CilType.Exp.show inv) in - let entry = Entry.location_invariant ~task ~location ~invariant in - entry :: acc - ) acc invs + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc invs + | None -> acc ) ns acc | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 9bdf8ac5a7..952696a5c4 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -213,7 +213,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: 138,139c144,151 @@ -225,7 +225,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: 143,144c155,228 @@ -237,7 +237,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > file_name: 04-priv_multi.c > file_hash: $FILE_HASH > line: 67 - > column: 7 + > column: 3 > function: main > location_invariant: > string: '! multithreaded || ((0 <= B && B <= 127) && B != 0)' From 16c97fde01a00b5ae8892bc8de0dea5c1070e298 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 12:56:37 +0300 Subject: [PATCH 058/103] Add cram test for relational mutex-meet flow-insensitive invariants --- .../regression/36-apron/12-traces-min-rpb1.t | 98 +++++++++++++++++++ tests/regression/36-apron/dune | 3 + 2 files changed, 101 insertions(+) create mode 100644 tests/regression/36-apron/12-traces-min-rpb1.t diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t new file mode 100644 index 0000000000..13cefb9557 --- /dev/null +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -0,0 +1,98 @@ + $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) + [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 18 + dead: 0 + total lines: 18 + [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) + [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 2 + total memory locations: 2 + +TODO: emit g == h + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 18 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "1" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: A_locked + expression: "0" + location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: A_locked + scope: global + type: int + initial: "0" diff --git a/tests/regression/36-apron/dune b/tests/regression/36-apron/dune index 099ec878b2..b14ebdfe64 100644 --- a/tests/regression/36-apron/dune +++ b/tests/regression/36-apron/dune @@ -8,3 +8,6 @@ (glob_files ??-*.c)) (locks /update_suite) (action (chdir ../../.. (run %{update_suite} group apron)))) + +(cram + (deps (glob_files *.c))) From 5650784effc4c077a7f7efed045c201f42b5748b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 13:04:36 +0300 Subject: [PATCH 059/103] Add InvariantGlobal interface to relational privatizations --- src/analyses/apron/relationAnalysis.apron.ml | 13 +++++++++++++ src/analyses/apron/relationPriv.apron.ml | 9 +++++++++ 2 files changed, 22 insertions(+) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index f1ea72d0a1..ba5b90525c 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -634,6 +634,16 @@ struct ) |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + let query_invariant_global ctx g = + (* TODO: option? *) + if ctx.ask (GhostVarAvailable Multithreaded) then ( + let var = WitnessGhost.to_varinfo Multithreaded in + let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) ctx.global g in + Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) + else + Invariant.none + let query ctx (type a) (q: a Queries.t): a Queries.result = let open Queries in let st = ctx.local in @@ -655,6 +665,9 @@ struct let vf' x = vf (Obj.repr x) in Priv.iter_sys_vars ctx.global vq vf' | Queries.Invariant context -> query_invariant ctx context + | Queries.InvariantGlobal g -> + let g: V.t = Obj.obj g in + query_invariant_global ctx g | _ -> Result.top q diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 66548c117c..f286287dbe 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -46,6 +46,9 @@ module type S = val thread_return: Q.ask -> (V.t -> G.t) -> (V.t -> G.t -> unit) -> ThreadIdDomain.Thread.t -> relation_components_t -> relation_components_t val iter_sys_vars: (V.t -> G.t) -> VarQuery.t -> V.t VarQuery.f -> unit (** [Queries.IterSysVars] for apron. *) + val invariant_global: Q.ask -> (V.t -> G.t) -> V.t -> Invariant.t + (** Returns flow-insensitive invariant for global unknown. *) + val invariant_vars: Q.ask -> (V.t -> G.t) -> relation_components_t -> varinfo list (** Returns global variables which are privatized. *) @@ -130,6 +133,7 @@ struct {rel = RD.top (); priv = startstate ()} let iter_sys_vars getg vq vf = () + let invariant_global ask getg g = Invariant.none let invariant_vars ask getg st = [] let init () = () @@ -410,6 +414,7 @@ struct {rel = getg (); priv = startstate ()} let iter_sys_vars getg vq vf = () (* TODO: or report singleton global for any Global query? *) + let invariant_global ask getg g = Invariant.none let invariant_vars ask getg st = protected_vars ask (* TODO: is this right? *) let finalize () = () @@ -684,6 +689,8 @@ struct let init () = () let finalize () = () + + let invariant_global ask getg g = Invariant.none (* TODO: implement *) end (** May written variables. *) @@ -1242,6 +1249,8 @@ struct | _ -> () let finalize () = () + + let invariant_global ask getg g = Invariant.none end module TracingPriv = functor (Priv: S) -> functor (RD: RelationDomain.RD) -> From d3565cb8a7903e8604ba89df0867aba8813e4f53 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 13:42:58 +0300 Subject: [PATCH 060/103] Implement relational mutex-meet flow-insensitive invariants --- src/analyses/apron/relationPriv.apron.ml | 19 ++++++++++++++++++- .../regression/36-apron/12-traces-min-rpb1.t | 12 ++++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index f286287dbe..a75e2ef113 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -690,7 +690,24 @@ struct let init () = () let finalize () = () - let invariant_global ask getg g = Invariant.none (* TODO: implement *) + let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function + | `Left m' as m -> (* mutex *) + if ask.f (GhostVarAvailable (Locked m')) then ( + let cpa = getg m in + let inv = + RD.invariant cpa + (* TODO: filters like query_invariant? *) + |> List.filter_map RD.cil_exp_of_lincons1 + |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + (* TODO: need to filter for MustBeProtectedBy like base mutex-meet? *) + in + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) + else + Invariant.none + | g -> (* global *) + Invariant.none (* TODO: ? *) end (** May written variables. *) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 13cefb9557..e05840429b 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c + $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) @@ -13,15 +13,13 @@ write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 10 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 unsafe: 2 total memory locations: 2 -TODO: emit g == h - $ yamlWitnessStrip < witness.yml - entry_type: ghost_update variable: multithreaded @@ -96,3 +94,9 @@ TODO: emit g == h scope: global type: int initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (A_locked || ((0LL - (long long )g) + (long long )h + >= 0LL && (long long )g - (long long )h >= 0LL))' + type: assertion + format: C From 1aa35d85b74c24e14c471b7d174dc441cccdbd72 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 14:46:48 +0300 Subject: [PATCH 061/103] Filter relational mutex-meet ghost invariant with keep_only_protected_globals lock does it too, so let's be safe. --- src/analyses/apron/relationPriv.apron.ml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index a75e2ef113..b73319b4df 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -693,13 +693,12 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) if ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = getg m in + let rel = keep_only_protected_globals ask m' (getg m) in let inv = - RD.invariant cpa + RD.invariant rel (* TODO: filters like query_invariant? *) |> List.filter_map RD.cil_exp_of_lincons1 |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none - (* TODO: need to filter for MustBeProtectedBy like base mutex-meet? *) in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) From c4a8936a2bd36d88cdc2909872aa6e6634098653 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 30 Apr 2024 14:53:57 +0300 Subject: [PATCH 062/103] Add filters to relational InvariantGlobal --- src/analyses/apron/relationAnalysis.apron.ml | 3 +-- src/analyses/apron/relationPriv.apron.ml | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/analyses/apron/relationAnalysis.apron.ml b/src/analyses/apron/relationAnalysis.apron.ml index ba5b90525c..397301b7bc 100644 --- a/src/analyses/apron/relationAnalysis.apron.ml +++ b/src/analyses/apron/relationAnalysis.apron.ml @@ -635,8 +635,7 @@ struct |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none let query_invariant_global ctx g = - (* TODO: option? *) - if ctx.ask (GhostVarAvailable Multithreaded) then ( + if GobConfig.get_bool "ana.relation.invariant.global" && ctx.ask (GhostVarAvailable Multithreaded) then ( let var = WitnessGhost.to_varinfo Multithreaded in let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) ctx.global g in Invariant.(of_exp (UnOp (LNot, Lval (GoblintCil.var var), GoblintCil.intType)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index b73319b4df..dcb3b166c3 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -693,12 +693,24 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) if ask.f (GhostVarAvailable (Locked m')) then ( + (* filters like query_invariant *) + let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in + let exact = GobConfig.get_bool "witness.invariant.exact" in + let rel = keep_only_protected_globals ask m' (getg m) in let inv = RD.invariant rel - (* TODO: filters like query_invariant? *) - |> List.filter_map RD.cil_exp_of_lincons1 - |> List.fold_left (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none + |> List.enum + |> Enum.filter_map (fun (lincons1: Apron.Lincons1.t) -> + (* filter one-vars and exact *) + (* TODO: exact filtering doesn't really work with octagon because it returns two SUPEQ constraints instead *) + if (one_var || GobApron.Lincons1.num_vars lincons1 >= 2) && (exact || Apron.Lincons1.get_typ lincons1 <> EQ) then + RD.cil_exp_of_lincons1 lincons1 + |> Option.filter (fun exp -> not (InvariantCil.exp_contains_tmp exp)) + else + None + ) + |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none in let var = WitnessGhost.to_varinfo (Locked m') in Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) From 535de765401c7a865c5c44be6b06f4aff85a7b65 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 7 May 2024 15:52:17 +0300 Subject: [PATCH 063/103] Add test with __VERIFIER_atomic_locked ghost variable --- tests/regression/29-svcomp/16-atomic_priv.t | 92 +++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 15425f68dd..d3826d8de3 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -81,3 +81,95 @@ string: '! multithreaded || myglobal == 5' type: assertion format: C + +Non-atomic privatization: + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) + [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) + [Warning][Assert] Assertion "myglobal == 5" is unknown. (16-atomic_priv.c:24:3-24:33) + [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:26:3-26:33) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 17 + dead: 0 + total lines: 17 + [Warning][Race] Memory location myglobal (race with conf. 110): (16-atomic_priv.c:8:5-8:17) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:13:3-13:13) + write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) + read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) + [Info][Witness] witness generation summary: + total generation entries: 9 + [Info][Race] Memory locations race summary: + safe: 0 + vulnerable: 0 + unsafe: 1 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "1" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + - entry_type: ghost_update + variable: __VERIFIER_atomic_locked + expression: "0" + location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: __VERIFIER_atomic_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || ((0 <= myglobal && myglobal <= 127) && myglobal != + 0)' + type: assertion + format: C From 6f3b6fbc6ab0e18560f6cbf5a409b46a6055022d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 7 May 2024 16:13:16 +0300 Subject: [PATCH 064/103] Treat __VERIFIER_atomic_locked as false in witnesses Others cannot observe anything else anyway. But in the atomic section could?! --- src/analyses/apron/relationPriv.apron.ml | 11 ++- src/analyses/basePriv.ml | 15 +++- src/analyses/mutexGhosts.ml | 5 +- src/witness/witnessGhostVar.ml | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 88 +-------------------- 5 files changed, 26 insertions(+), 95 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index dcb3b166c3..f14700f437 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -692,7 +692,8 @@ struct let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function | `Left m' as m -> (* mutex *) - if ask.f (GhostVarAvailable (Locked m')) then ( + let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in + if atomic || ask.f (GhostVarAvailable (Locked m')) then ( (* filters like query_invariant *) let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in @@ -712,8 +713,12 @@ struct ) |> Enum.fold (fun acc x -> Invariant.(acc && of_exp x)) Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if atomic then + inv + else ( + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) ) else Invariant.none diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 799290c4fe..af88cfb742 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -333,7 +333,8 @@ struct let invariant_global (ask: Q.ask) getg = function | `Left m' as m -> (* mutex *) - if ask.f (GhostVarAvailable (Locked m')) then ( + let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in + if atomic || ask.f (GhostVarAvailable (Locked m')) then ( let cpa = getg m in let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then @@ -343,8 +344,12 @@ struct acc ) cpa Invariant.none in - let var = WitnessGhost.to_varinfo (Locked m') in - Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + if atomic then + inv + else ( + let var = WitnessGhost.to_varinfo (Locked m') in + Invariant.(of_exp (Lval (GoblintCil.var var)) || inv) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) + ) ) else Invariant.none @@ -864,7 +869,9 @@ struct else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) Q.AD.fold (fun m acc -> - if ask.f (GhostVarAvailable (Locked m)) then ( + if LockDomain.Addr.equal m (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) then + acc + else if ask.f (GhostVarAvailable (Locked m)) then ( let var = WitnessGhost.to_varinfo (Locked m) in Invariant.(of_exp (Lval (GoblintCil.var var)) || acc) [@coverage off] (* bisect_ppx cannot handle redefined (||) *) ) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 75195e4662..eaa15df8e6 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -59,8 +59,9 @@ struct end let event ctx e octx = + let verifier_atomic_addr = LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var in begin match e with - | Events.Lock (l, _) -> + | Events.Lock (l, _) when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in @@ -70,7 +71,7 @@ struct ) locked ); ) - | Events.Unlock l -> + | Events.Unlock l when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index cec61b0e2d..7979d23173 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -9,7 +9,7 @@ let name_varinfo = function | Locked (Addr (v, os)) -> let name = if CilType.Varinfo.equal v LibraryFunctions.verifier_atomic_var then - "__VERIFIER_atomic" + invalid_arg "__VERIFIER_atomic" else if RichVarinfo.BiVarinfoMap.Collection.mem_varinfo v then Printf.sprintf "alloc_%s%d" (if v.vid < 0 then "m" else "") (abs v.vid) (* turn minus into valid C name *) diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index d3826d8de3..b10265d4e8 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -30,52 +30,11 @@ line: 23 column: 3 function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: __VERIFIER_atomic_locked - scope: global - type: int - initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' @@ -99,7 +58,7 @@ Non-atomic privatization: write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -116,55 +75,14 @@ Non-atomic privatization: line: 23 column: 3 function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: __VERIFIER_atomic_locked - expression: "0" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - entry_type: ghost_variable variable: multithreaded scope: global type: int initial: "0" - - entry_type: ghost_variable - variable: __VERIFIER_atomic_locked - scope: global - type: int - initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (__VERIFIER_atomic_locked || myglobal == 5)' + string: '! multithreaded || myglobal == 5' type: assertion format: C - entry_type: flow_insensitive_invariant From 2e6673f72e1e3df8c67b9c0c21aec9f45e1c4ab2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 8 May 2024 11:41:45 +0300 Subject: [PATCH 065/103] Disable 13-privatized/04-priv_multi cram test on OSX OSX has its own weird diff. --- tests/regression/13-privatized/dune | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/regression/13-privatized/dune b/tests/regression/13-privatized/dune index 23c0dd3290..9227128b15 100644 --- a/tests/regression/13-privatized/dune +++ b/tests/regression/13-privatized/dune @@ -1,2 +1,6 @@ (cram (deps (glob_files *.c))) + +(cram + (applies_to 04-priv_multi) + (enabled_if (<> %{system} macosx))) From b7582a4c5495e35a24974228785817b01711a37c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 8 May 2024 11:43:03 +0300 Subject: [PATCH 066/103] Make 36-apron/12-traces-min-rpb1 cram test warnings deterministic Needed for OSX CI to pass. --- .../regression/36-apron/12-traces-min-rpb1.t | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index e05840429b..7aca1dea0b 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,24 +1,24 @@ - $ goblint --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box - [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) + [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) - [Info][Deadcode] Logical lines of code (LLoC) summary: - live: 18 - dead: 0 - total lines: 18 - [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) - write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) - read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Warning][Race] Memory location g (race with conf. 110): (12-traces-min-rpb1.c:7:5-7:10) write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:14:3-14:8) read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & g) (12-traces-min-rpb1.c:27:3-27:26) - [Info][Witness] witness generation summary: - total generation entries: 10 + [Warning][Race] Memory location h (race with conf. 110): (12-traces-min-rpb1.c:8:5-8:10) + write with [lock:{A}, thread:[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:15:3-15:8) + read with [mhp:{created={[main, t_fun@12-traces-min-rpb1.c:25:3-25:40]}}, thread:[main]] (conf. 110) (exp: & h) (12-traces-min-rpb1.c:27:3-27:26) [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 unsafe: 2 total memory locations: 2 + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 18 + dead: 0 + total lines: 18 + [Info][Witness] witness generation summary: + total generation entries: 10 $ yamlWitnessStrip < witness.yml - entry_type: ghost_update From cad5f6e6c3b047cc30061188b57889b87a8b767a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 20 May 2024 13:03:12 +0300 Subject: [PATCH 067/103] Add BasePriv invariant_global tracing --- src/analyses/basePriv.ml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index af88cfb742..cbc11070d3 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -1917,6 +1917,17 @@ struct if M.tracing then M.traceu "priv" "-> %a" BaseComponents.pretty r; r + let invariant_global ask getg g = + if M.tracing then M.traceli "priv" "invariant_global %a" V.pretty g; + let getg x = + let r = getg x in + if M.tracing then M.trace "priv" "getg %a -> %a" V.pretty x G.pretty r; + r + in + let r = invariant_global ask getg g in + if M.tracing then M.traceu "priv" "-> %a" Invariant.pretty r; + r + end let priv_module: (module S) Lazy.t = From bd329e16f72f296bdf88f46d31fcfc4477db3ffc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 21 May 2024 11:53:44 +0300 Subject: [PATCH 068/103] Fix mutex-meet invariant_global not including MUTEX_INITS --- src/analyses/apron/relationPriv.apron.ml | 4 ++-- src/analyses/basePriv.ml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index cb71884c8c..5ffb96650c 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -694,14 +694,14 @@ struct let finalize () = () let invariant_global (ask: Q.ask) (getg: V.t -> G.t): V.t -> Invariant.t = function - | `Left m' as m -> (* mutex *) + | `Left m' -> (* mutex *) let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( (* filters like query_invariant *) let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in - let rel = keep_only_protected_globals ask m' (getg m) in + let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* TODO: disjunct with mutex_inits instead of join? *) let inv = RD.invariant rel |> List.enum diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index cbc11070d3..c244e7f3bf 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -250,7 +250,7 @@ struct let invariant_global ask getg = function | `Right g' -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g' + ValueDomain.invariant_global (read_unprotected_global getg) g' (* TODO: disjunct with mutex_inits instead of join? *) | _ -> (* mutex *) Invariant.none @@ -332,10 +332,10 @@ struct include PerMutexPrivBase let invariant_global (ask: Q.ask) getg = function - | `Left m' as m -> (* mutex *) + | `Left m' -> (* mutex *) let atomic = LockDomain.Addr.equal m' (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = getg m in + let cpa = get_m_with_mutex_inits ask getg m' in (* TODO: disjunct with mutex_inits instead of join? *) let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in @@ -688,7 +688,7 @@ struct let invariant_global ask getg = function | `Middle g -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g + ValueDomain.invariant_global (read_unprotected_global getg) g (* TODO: disjunct with mutex_inits instead of join? *) | `Left _ | `Right _ -> (* mutex or thread *) Invariant.none From 2a79e42601bcf03c3a446fd7dceafc22096358d1 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 4 Jun 2024 10:45:25 +0300 Subject: [PATCH 069/103] Add comment about multiple protecting mutexes for ghost invariants --- src/analyses/basePriv.ml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index c244e7f3bf..be261d96b7 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -868,6 +868,10 @@ struct Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. + It should be possible to be more precise because writes only happen with all of them held, + but conjunction is unsound when one of the mutexes is temporarily unlocked. + Hypothetical read-protection is also somehow relevant. *) Q.AD.fold (fun m acc -> if LockDomain.Addr.equal m (LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var) then acc From 2e42c7bf1c664d07ab5844246338547f4d28f3c8 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 12:36:10 +0300 Subject: [PATCH 070/103] Add ghost_variable and ghost_update YAML entry types to option --- conf/svcomp-ghost.json | 4 +++- src/analyses/mutexGhosts.ml | 3 +++ src/config/options.schema.json | 4 +++- src/witness/witnessGhost.ml | 3 +++ tests/regression/13-privatized/04-priv_multi.t | 4 ++-- tests/regression/13-privatized/25-struct_nr.t | 2 +- tests/regression/13-privatized/74-mutex.t | 6 +++--- tests/regression/13-privatized/92-idx_priv.t | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 4 ++-- tests/regression/36-apron/12-traces-min-rpb1.t | 2 +- tests/regression/56-witness/64-ghost-multiple-protecting.t | 6 +++--- tests/regression/56-witness/65-ghost-ambiguous-lock.t | 2 +- tests/regression/56-witness/66-ghost-alloc-lock.t | 2 +- tests/regression/56-witness/67-ghost-no-unlock.t | 2 +- tests/regression/56-witness/68-ghost-ambiguous-idx.t | 2 +- 15 files changed, 29 insertions(+), 19 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 229dd9ef46..84f127eb91 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -116,7 +116,9 @@ "enabled": true, "format-version": "0.1", "entry-types": [ - "flow_insensitive_invariant" + "flow_insensitive_invariant", + "ghost_variable", + "ghost_update" ] }, "invariant": { diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 159498cfb1..6e95504731 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -96,6 +96,9 @@ struct | Locked _ -> false | Multithreaded -> true + let ghost_var_available ctx v = + WitnessGhost.enabled () && ghost_var_available ctx v + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | GhostVarAvailable v -> ghost_var_available ctx v diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 4a77aae5f0..779b9bbf65 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2580,7 +2580,9 @@ "precondition_loop_invariant", "loop_invariant_certificate", "precondition_loop_invariant_certificate", - "invariant_set" + "invariant_set", + "ghost_variable", + "ghost_update" ] }, "default": [ diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index cdd26b36aa..91d513ceae 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,5 +1,8 @@ (** Ghost variables for YAML witnesses. *) +let enabled () = + YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type + module Var = WitnessGhostVar include Var diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 952696a5c4..576c89ad4d 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index f3ebcd1c52..342cfaf99c 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index a00f49eb1a..f6f2fa8463 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -84,7 +84,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -150,7 +150,7 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index 64a3309009..bd6db7e2ef 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index b10265d4e8..83bc201a6c 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -43,7 +43,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 7aca1dea0b..1c3253afbc 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 53323355c5..943934a7be 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -144,7 +144,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -295,7 +295,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index 708e27ca64..d7d57d8a00 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index e4d128b71e..e4268ec1cb 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index 491dd9cf44..aed0ac3414 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 48837fcabb..9f50ab7429 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: From e7931ffe4afc2be4872b15d94a4ab3aa4ed66453 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 12:53:02 +0300 Subject: [PATCH 071/103] Make InvariantGlobalNodes query lazy in YAML witness generation --- src/witness/yamlWitness.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index b7bf11a31c..fd8f4b5249 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -325,7 +325,7 @@ struct (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( - let ns = R.ask_global InvariantGlobalNodes in + let ns = lazy (R.ask_global InvariantGlobalNodes) in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) @@ -352,7 +352,7 @@ struct entry :: acc ) acc invs | None -> acc - ) ns acc + ) (Lazy.force ns) acc | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end From 36ff6217074eb8c25a2528979ebc634d3cba789e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 5 Jun 2024 13:46:04 +0300 Subject: [PATCH 072/103] Fix comment about YamlEntryGlobal --- src/witness/yamlWitness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index fd8f4b5249..596a35f631 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -364,7 +364,7 @@ struct entries in - (* Generate flow-insensitive invariants *) + (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = if true then ( GHT.fold (fun g v acc -> From 7fcb10cd0fcb4c4f68d43a7bb60fec9d7cfc64d5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 18 Jun 2024 17:20:55 +0300 Subject: [PATCH 073/103] Handle pthread_rwlock_t as opaque mutex in base analysis Avoids unsound rwlock struct content invariants in witnesses. --- src/cdomain/value/cdomains/valueDomain.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdomain/value/cdomains/valueDomain.ml b/src/cdomain/value/cdomains/valueDomain.ml index de64fde807..09593fb614 100644 --- a/src/cdomain/value/cdomains/valueDomain.ml +++ b/src/cdomain/value/cdomains/valueDomain.ml @@ -120,7 +120,7 @@ struct | _ -> false let is_mutex_type (t: typ): bool = match t with - | TNamed (info, attr) -> info.tname = "pthread_mutex_t" || info.tname = "spinlock_t" || info.tname = "pthread_spinlock_t" || info.tname = "pthread_cond_t" + | TNamed (info, attr) -> info.tname = "pthread_mutex_t" || info.tname = "spinlock_t" || info.tname = "pthread_spinlock_t" || info.tname = "pthread_cond_t" || info.tname = "pthread_rwlock_t" | TInt (IInt, attr) -> hasAttribute "mutex" attr | _ -> false From c18061e000b830157f17f09c544320a83f9d756a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:26:54 +0300 Subject: [PATCH 074/103] Remove pthreadMutexType from ghost witness tests It is now enabled by default and default mutex type is assumed non-recursive now. --- .../regression/13-privatized/04-priv_multi.t | 4 +-- tests/regression/13-privatized/25-struct_nr.t | 2 +- tests/regression/13-privatized/74-mutex.c | 4 +-- tests/regression/13-privatized/74-mutex.t | 26 +++++++++---------- tests/regression/13-privatized/92-idx_priv.t | 2 +- tests/regression/29-svcomp/16-atomic_priv.t | 4 +-- .../regression/36-apron/12-traces-min-rpb1.t | 2 +- .../56-witness/64-ghost-multiple-protecting.c | 2 +- .../56-witness/64-ghost-multiple-protecting.t | 6 ++--- .../56-witness/65-ghost-ambiguous-lock.c | 2 +- .../56-witness/65-ghost-ambiguous-lock.t | 2 +- .../56-witness/66-ghost-alloc-lock.c | 8 +++--- .../56-witness/66-ghost-alloc-lock.t | 26 +++++++++---------- .../56-witness/67-ghost-no-unlock.c | 2 +- .../56-witness/67-ghost-no-unlock.t | 2 +- .../56-witness/68-ghost-ambiguous-idx.t | 2 +- 16 files changed, 48 insertions(+), 48 deletions(-) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index 576c89ad4d..b1a45dd917 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index 342cfaf99c..88f205a431 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) diff --git a/tests/regression/13-privatized/74-mutex.c b/tests/regression/13-privatized/74-mutex.c index 7c57688238..8ed9448b7b 100644 --- a/tests/regression/13-privatized/74-mutex.c +++ b/tests/regression/13-privatized/74-mutex.c @@ -29,8 +29,8 @@ void* producer() int main() { pthread_t tid; - pthread_mutexattr_t mutexattr; pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_NORMAL); - pthread_mutex_init(&m, &mutexattr); + + pthread_mutex_init(&m, 0); pthread_create(&tid, 0, producer, 0); pthread_mutex_lock(&m); diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index f6f2fa8463..8999d394ec 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,11 +1,11 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -84,14 +84,14 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -138,9 +138,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 @@ -150,14 +150,14 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: total generation entries: 9 @@ -241,9 +241,9 @@ Should also work with earlyglobs. [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) [Warning][Deadcode] Logical lines of code (LLoC) summary: - live: 15 + live: 14 dead: 1 - total lines: 16 + total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Race] Memory locations race summary: safe: 1 diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index bd6db7e2ef..b157dfed4b 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index 83bc201a6c..eea47295d5 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -43,7 +43,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 1c3253afbc..df34013d16 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -1,4 +1,4 @@ - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.c b/tests/regression/56-witness/64-ghost-multiple-protecting.c index 589aa92bff..699d133f2b 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.c +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include int g1, g2; diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index 943934a7be..e78d0d75aa 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -144,7 +144,7 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 @@ -295,7 +295,7 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.c b/tests/regression/56-witness/65-ghost-ambiguous-lock.c index b1df0ee2e8..f45334e755 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.c +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index d7d57d8a00..a6e0c12b74 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.c b/tests/regression/56-witness/66-ghost-alloc-lock.c index 2c1028564a..073540b9db 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.c +++ b/tests/regression/56-witness/66-ghost-alloc-lock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 +// PARAM: --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 #include #include @@ -18,11 +18,11 @@ void *t_fun(void *arg) { return NULL; } -int main() { pthread_mutexattr_t attr; pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL); // https://github.com/goblint/analyzer/pull/1414 +int main() { m1 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m1, &attr); + pthread_mutex_init(m1, NULL); m2 = malloc(sizeof(pthread_mutex_t)); - pthread_mutex_init(m2, &attr); + pthread_mutex_init(m2, NULL); pthread_t id; pthread_create(&id, NULL, t_fun, NULL); diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index e4268ec1cb..8e45272538 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -24,7 +24,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -33,7 +33,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -42,7 +42,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -51,7 +51,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -60,7 +60,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -69,7 +69,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "1" location: file_name: 66-ghost-alloc-lock.c @@ -78,7 +78,7 @@ column: 3 function: t_fun - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -87,7 +87,7 @@ column: 3 function: main - entry_type: ghost_update - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked expression: "0" location: file_name: 66-ghost-alloc-lock.c @@ -101,23 +101,23 @@ type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m817990718_locked + variable: alloc_m861095507_locked scope: global type: int initial: "0" - entry_type: ghost_variable - variable: alloc_m334174073_locked + variable: alloc_m559918035_locked scope: global type: int initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m817990718_locked || g2 == 0)' + string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (alloc_m334174073_locked || g1 == 0)' + string: '! multithreaded || (alloc_m559918035_locked || g1 == 0)' type: assertion format: C - entry_type: flow_insensitive_invariant diff --git a/tests/regression/56-witness/67-ghost-no-unlock.c b/tests/regression/56-witness/67-ghost-no-unlock.c index fc10b919d0..69ad571118 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.c +++ b/tests/regression/56-witness/67-ghost-no-unlock.c @@ -1,4 +1,4 @@ -// PARAM: --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType +// PARAM: --set ana.activated[+] mutexGhosts #include #include diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index aed0ac3414..85b7a0b897 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 9f50ab7429..02cecfd8f6 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.activated[+] pthreadMutexType --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: From 6055e8dd7e768d2b061c16b9da61a579e120b146 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:29:15 +0300 Subject: [PATCH 075/103] Activate abortUnless in svcomp-ghost conf also --- conf/svcomp-ghost.json | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 84f127eb91..108b261322 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -31,6 +31,7 @@ "region", "thread", "threadJoins", + "abortUnless", "mutexGhosts", "pthreadMutexType" ], From 6e793142a53781763f9232d31302c5d21fea3b47 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 31 Jul 2024 11:31:52 +0300 Subject: [PATCH 076/103] Update TODO comment about base earlyglobs flow-insensitive invariants --- src/analyses/base.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index 4ae2fc711c..782b5662c6 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1247,8 +1247,8 @@ struct let query_invariant_global ctx g = if GobConfig.get_bool "ana.base.invariant.enabled" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. - Otherwise, the values of globals in single-threaded mode are not accounted for. *) - (* TODO: account for single-threaded values without earlyglobs. *) + Otherwise, the values of globals in single-threaded mode are not accounted for. + They are also made sound without earlyglobs using the multithreaded mode ghost variable. *) match g with | `Left g' -> (* priv *) let inv = Priv.invariant_global (Analyses.ask_of_ctx ctx) (priv_getg ctx.global) g' in From d937d68202ff9c4d43721f5439c64c3c4a1a3bbe Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:53:06 +0300 Subject: [PATCH 077/103] Add options ana.base.invariant.local and ana.base.invariant.global --- src/analyses/base.ml | 42 ++++++++++++++++++++++++++-------- src/config/options.schema.json | 12 ++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/analyses/base.ml b/src/analyses/base.ml index aa11584f53..f9267ba1d0 100644 --- a/src/analyses/base.ml +++ b/src/analyses/base.ml @@ -1183,6 +1183,9 @@ struct not is_alloc || (is_alloc && not (ctx.ask (Queries.IsHeapVar v))) let query_invariant ctx context = + let keep_local = GobConfig.get_bool "ana.base.invariant.local" in + let keep_global = GobConfig.get_bool "ana.base.invariant.global" in + let cpa = ctx.local.BaseDomain.cpa in let ask = Analyses.ask_of_ctx ctx in @@ -1195,6 +1198,13 @@ struct in let module I = ValueDomain.ValueInvariant (Arg) in + let var_filter v = + if is_global ask v then + keep_global + else + keep_local + in + let var_invariant ?offset v = if not (InvariantCil.var_is_heap v) then I.key_invariant v ?offset (Arg.find v) @@ -1205,14 +1215,23 @@ struct if Lval.Set.is_top context.Invariant.lvals then ( if !earlyglobs || ThreadFlag.has_ever_been_multi ask then ( let cpa_invariant = - CPA.fold (fun k v a -> - if not (is_global ask k) then - Invariant.(a && var_invariant k) - else - a - ) cpa Invariant.none + if keep_local then ( + CPA.fold (fun k v a -> + if not (is_global ask k) then + Invariant.(a && var_invariant k) + else + a + ) cpa Invariant.none + ) + else + Invariant.none + in + let priv_vars = + if keep_global then + Priv.invariant_vars ask (priv_getg ctx.global) ctx.local + else + [] in - let priv_vars = Priv.invariant_vars ask (priv_getg ctx.global) ctx.local in let priv_invariant = List.fold_left (fun acc v -> Invariant.(var_invariant v && acc) @@ -1222,7 +1241,10 @@ struct ) else ( CPA.fold (fun k v a -> - Invariant.(a && var_invariant k) + if var_filter k then + Invariant.(a && var_invariant k) + else + a ) cpa Invariant.none ) ) @@ -1230,7 +1252,7 @@ struct Lval.Set.fold (fun k a -> let i = match k with - | (Var v, offset) when not (InvariantCil.var_is_heap v) -> + | (Var v, offset) when var_filter v && not (InvariantCil.var_is_heap v) -> (try I.key_invariant_lval v ~offset ~lval:k (Arg.find v) with Not_found -> Invariant.none) | _ -> Invariant.none in @@ -1245,7 +1267,7 @@ struct Invariant.none let query_invariant_global ctx g = - if GobConfig.get_bool "ana.base.invariant.enabled" then ( + if GobConfig.get_bool "ana.base.invariant.enabled" && GobConfig.get_bool "ana.base.invariant.global" then ( (* Currently these global invariants are only sound with earlyglobs enabled for both single- and multi-threaded programs. Otherwise, the values of globals in single-threaded mode are not accounted for. They are also made sound without earlyglobs using the multithreaded mode ghost variable. *) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 16c9d7e8ef..7121713c33 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -795,6 +795,18 @@ "type": "boolean", "default": true }, + "local": { + "title": "ana.base.invariant.local", + "description": "Keep local variables in invariants", + "type": "boolean", + "default": true + }, + "global": { + "title": "ana.base.invariant.global", + "description": "Keep global variables in invariants", + "type": "boolean", + "default": true + }, "blobs": { "title": "ana.base.invariant.blobs", "description": "Whether to dump assertions about all blobs. Enabling this option may lead to unsound asserts.", From fbc9e62c8c4ca209759fa2be86ba393c64b51cf4 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 11:58:02 +0300 Subject: [PATCH 078/103] Add option ana.var_eq.invariant.enabled --- src/analyses/varEq.ml | 2 +- src/config/options.schema.json | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/analyses/varEq.ml b/src/analyses/varEq.ml index 8ece99d6e8..db1228a3dd 100644 --- a/src/analyses/varEq.ml +++ b/src/analyses/varEq.ml @@ -564,7 +564,7 @@ struct let r = eq_set_clos e ctx.local in if M.tracing then M.tracel "var_eq" "equalset %a = %a" d_plainexp e Queries.ES.pretty r; r - | Queries.Invariant context when GobConfig.get_bool "witness.invariant.exact" -> (* only exact equalities here *) + | Queries.Invariant context when GobConfig.get_bool "ana.var_eq.invariant.enabled" && GobConfig.get_bool "witness.invariant.exact" -> (* only exact equalities here *) let scope = Node.find_fundec ctx.node in D.invariant ~scope ctx.local | _ -> Queries.Result.top x diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 7121713c33..d9174b9aa1 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -1154,6 +1154,26 @@ } }, "additionalProperties": false + }, + "var_eq": { + "title": "ana.var_eq", + "type": "object", + "properties": { + "invariant": { + "title": "ana.var_eq.invariant", + "type": "object", + "properties": { + "enabled": { + "title": "ana.var_eq.invariant.enabled", + "description": "Generate var_eq analysis invariants", + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false } }, "additionalProperties": false From 58aaf53abd7f0d73cd525648256670da1caf2c9e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 7 Aug 2024 12:10:11 +0300 Subject: [PATCH 079/103] Update svcomp-ghost conf --- conf/svcomp-ghost.json | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index 108b261322..dc611695dc 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -71,6 +71,27 @@ "base": { "arrays": { "domain": "partitioned" + }, + "invariant": { + "local": false, + "global": true + } + }, + "relation": { + "invariant": { + "local": false, + "global": true, + "one-var": false + } + }, + "apron": { + "invariant": { + "diff-box": true + } + }, + "var_eq": { + "invariant": { + "enabled": false } }, "race": { @@ -123,10 +144,10 @@ ] }, "invariant": { - "loop-head": true, + "loop-head": false, "after-lock": true, - "other": true, - "accessed": true, + "other": false, + "accessed": false, "exact": true, "all-locals": false, "flow_insensitive-as-location": true, From f20ed620a1db2acd88b002b096294d8836ed4c55 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 8 Aug 2024 10:58:13 +0300 Subject: [PATCH 080/103] Re-enable witness.invariant.{loop-head,other} in svcomp-ghost conf for flow-insensitive location invariants to work --- conf/svcomp-ghost.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index dc611695dc..ce308c5e52 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -144,9 +144,9 @@ ] }, "invariant": { - "loop-head": false, + "loop-head": true, "after-lock": true, - "other": false, + "other": true, "accessed": false, "exact": true, "all-locals": false, From 9c604183f6bd7765fba521dbb7da7efcb9cdf129 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 11:37:34 +0300 Subject: [PATCH 081/103] Add YAML witness ghost_instrumentation entry type --- src/config/options.schema.json | 3 +- src/witness/yamlWitness.ml | 25 +++++++++ src/witness/yamlWitnessType.ml | 99 ++++++++++++++++++++++++++++++++++ tests/util/yamlWitnessStrip.ml | 5 ++ 4 files changed, 131 insertions(+), 1 deletion(-) diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 424992c3de..06b6f26359 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2648,7 +2648,8 @@ "precondition_loop_invariant_certificate", "invariant_set", "ghost_variable", - "ghost_update" + "ghost_update", + "ghost_instrumentation" ] }, "default": [ diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index d3988f8edb..cc435a38ac 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -160,6 +160,31 @@ struct }; metadata = metadata ~task (); } + + let ghost_variable' ~variable ~type_ ~(initial): GhostInstrumentation.Variable.t = { + name = variable; + scope = "global"; + type_; + initial; + } + + let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { + ghost_variable = variable; + expression; + } + + let ghost_location_update' ~location ~(updates): GhostInstrumentation.LocationUpdate.t = { + location; + updates; + } + + let ghost_instrumentation ~task ~variables ~(location_updates): Entry.t = { + entry_type = GhostInstrumentation { + ghost_variables = variables; + ghost_updates = location_updates; + }; + metadata = metadata ~task (); + } end let yaml_entries_to_file yaml_entries file = diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 4bdb730b82..72afbf432b 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -485,6 +485,99 @@ struct {variable; expression; location} end +module GhostInstrumentation = +struct + + module Variable = + struct + type t = { + name: string; + scope: string; + type_: string; + initial: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {name; scope; type_; initial} = + `O [ + ("name", `String name); + ("scope", `String scope); + ("type", `String type_); + ("initial", `String initial); + ] + + let of_yaml y = + let open GobYaml in + let+ name = y |> find "name" >>= to_string + and+ scope = y |> find "scope" >>= to_string + and+ type_ = y |> find "type" >>= to_string + and+ initial = y |> find "initial" >>= to_string in + {name; scope; type_; initial} + end + + module Update = + struct + type t = { + ghost_variable: string; + expression: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {ghost_variable; expression} = + `O [ + ("ghost_variable", `String ghost_variable); + ("expression", `String expression); + ] + + let of_yaml y = + let open GobYaml in + let+ ghost_variable = y |> find "ghost_variable" >>= to_string + and+ expression = y |> find "expression" >>= to_string in + {ghost_variable; expression} + end + + module LocationUpdate = + struct + type t = { + location: Location.t; + updates: Update.t list; + } + [@@deriving eq, ord, hash] + + let to_yaml {location; updates} = + `O [ + ("location", Location.to_yaml location); + ("updates", `A (List.map Update.to_yaml updates)); + ] + + let of_yaml y = + let open GobYaml in + let+ location = y |> find "location" >>= Location.of_yaml + and+ updates = y |> find "updates" >>= list >>= list_map Update.of_yaml in + {location; updates} + end + + type t = { + ghost_variables: Variable.t list; + ghost_updates: LocationUpdate.t list; + } + [@@deriving eq, ord, hash] + + let entry_type = "ghost_instrumentation" + + let to_yaml' {ghost_variables; ghost_updates} = + [ + ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); + ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + ] + + let of_yaml y = + let open GobYaml in + let+ ghost_variables = y |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml + and+ ghost_updates = y |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in + {ghost_variables; ghost_updates} +end + (* TODO: could maybe use GADT, but adds ugly existential layer to entry type pattern matching *) module EntryType = struct @@ -498,6 +591,7 @@ struct | InvariantSet of InvariantSet.t | GhostVariable of GhostVariable.t | GhostUpdate of GhostUpdate.t + | GhostInstrumentation of GhostInstrumentation.t [@@deriving eq, ord, hash] let entry_type = function @@ -510,6 +604,7 @@ struct | InvariantSet _ -> InvariantSet.entry_type | GhostVariable _ -> GhostVariable.entry_type | GhostUpdate _ -> GhostUpdate.entry_type + | GhostInstrumentation _ -> GhostInstrumentation.entry_type let to_yaml' = function | LocationInvariant x -> LocationInvariant.to_yaml' x @@ -521,6 +616,7 @@ struct | InvariantSet x -> InvariantSet.to_yaml' x | GhostVariable x -> GhostVariable.to_yaml' x | GhostUpdate x -> GhostUpdate.to_yaml' x + | GhostInstrumentation x -> GhostInstrumentation.to_yaml' x let of_yaml y = let open GobYaml in @@ -552,6 +648,9 @@ struct else if entry_type = GhostUpdate.entry_type then let+ x = y |> GhostUpdate.of_yaml in GhostUpdate x + else if entry_type = GhostInstrumentation.entry_type then + let+ x = y |> GhostInstrumentation.of_yaml in + GhostInstrumentation x else Error (`Msg ("entry_type " ^ entry_type)) end diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 211a8a0e1a..4d7b446bab 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -26,6 +26,9 @@ struct in {invariant_type} in + let ghost_location_update_strip_file_hash (x: GhostInstrumentation.LocationUpdate.t): GhostInstrumentation.LocationUpdate.t = + {x with location = location_strip_file_hash x.location} + in let entry_type: EntryType.t = match entry_type with | LocationInvariant x -> @@ -46,6 +49,8 @@ struct GhostVariable x (* no location to strip *) | GhostUpdate x -> GhostUpdate {x with location = location_strip_file_hash x.location} + | GhostInstrumentation x -> + GhostInstrumentation {x with ghost_updates = List.map ghost_location_update_strip_file_hash x.ghost_updates} in {entry_type} From d22065396f057689adf10ee950d623fb999bc4b7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:27:58 +0300 Subject: [PATCH 082/103] Add ghost_instrumentation support to mutexGhosts --- src/analyses/mutexGhosts.ml | 84 ++++++++++++++++++++-- src/witness/witnessGhost.ml | 22 +++++- tests/regression/13-privatized/74-mutex.t | 87 +++++++++++++++++++++++ 3 files changed, 186 insertions(+), 7 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 7bc4423f04..09afc41baa 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,17 +10,19 @@ struct include UnitAnalysis.Spec let name () = "mutexGhosts" - module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) + (* module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) *) module V = struct - include Printable.Either3 (Node) (LockDomain.MustLock) (ThreadCreate) + include Printable.Either3 (Node) (LockDomain.MustLock) (BoolDomain.Bool) let node x = `Left x let lock x = `Middle x - let threadcreate = `Right () + let threadcreate = `Right false + let update = `Right true let is_write_only = function | `Left _ -> false | `Middle _ -> true - | `Right _ -> false + | `Right false -> false + | `Right true -> true end module Locked = @@ -53,9 +55,11 @@ struct | `Bot -> NodeSet.bot () | `Lifted2 (`Lifted2 x) -> x | _ -> failwith "MutexGhosts.threadcreate" + let update = threadcreate let create_node node = `Lifted1 node let create_lock lock = `Lifted2 (`Lifted1 lock) let create_threadcreate threadcreate = `Lifted2 (`Lifted2 threadcreate) + let create_update = create_threadcreate end let mustlock_of_addr (addr: LockDomain.Addr.t): LockDomain.MustLock.t option = @@ -69,6 +73,7 @@ struct | Events.Lock (l, _) when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.singleton l, Unlocked.bot (), MultiThread.bot ())); if !AnalysisState.postsolving then ( + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); let (locked, _, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal locked > 1 then ( Locked.iter (fun lock -> @@ -81,6 +86,7 @@ struct | Events.Unlock l when not (LockDomain.Addr.equal l verifier_atomic_addr) -> ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.singleton l, MultiThread.bot ())); if !AnalysisState.postsolving then ( + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); let (_, unlocked, _) = G.node (ctx.global (V.node ctx.prev_node)) in if Locked.cardinal unlocked > 1 then ( Locked.iter (fun lock -> @@ -91,7 +97,9 @@ struct ); ) | Events.EnterMultiThreaded -> - ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)) + ctx.sideg (V.node ctx.prev_node) (G.create_node (Locked.bot (), Unlocked.bot (), true)); + if !AnalysisState.postsolving then + ctx.sideg V.update (G.create_update (NodeSet.singleton ctx.prev_node)); | _ -> () end; ctx.local @@ -113,7 +121,7 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with - | `Left g' -> + | `Left g' when YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type -> let (locked, unlocked, multithread) = G.node (ctx.global g) in let g = g' in let entries = @@ -161,6 +169,70 @@ struct entries in entries + | `Right true when YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type -> + let nodes = G.update (ctx.global g) in + let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> + let (locked, unlocked, multithread) = G.node (ctx.global (V.node node)) in + let variables' = + (* TODO: do variable_entry-s only once *) + Locked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let variable = WitnessGhost.variable' (Locked l) in + if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable acc then (* TODO: be efficient *) + acc + else + variable :: acc + | _ -> + acc + ) (Locked.union locked unlocked) variables + in + let updates = + Locked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let update = WitnessGhost.update' (Locked l) GoblintCil.one in + update :: acc + | _ -> + acc + ) locked [] + in + let updates = + Unlocked.fold (fun l acc -> + match mustlock_of_addr l with + | Some l when ghost_var_available ctx (Locked l) -> + let update = WitnessGhost.update' (Locked l) GoblintCil.zero in + update :: acc + | _ -> + acc + ) unlocked updates + in + let (variables', updates) = + if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( + if ghost_var_available ctx Multithreaded then ( + let variable = WitnessGhost.variable' Multithreaded in + let update = WitnessGhost.update' Multithreaded GoblintCil.one in + let variables' = + if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable variables' then (* TODO: be efficient *) + variables' + else + variable :: variables' + in + (variables', update :: updates) + ) + else + (variables', updates) + ) + else + (variables', updates) + in + let location_update = WitnessGhost.location_update' ~node ~updates in + (variables', location_update :: location_updates) + ) nodes ([], []) + in + let entry = WitnessGhost.instrumentation_entry ~task ~variables ~location_updates in + Queries.YS.singleton entry + | `Left _ -> Queries.Result.top q | `Middle _ -> Queries.Result.top q | `Right _ -> Queries.Result.top q end diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 91d513ceae..3535e8a347 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,7 +1,7 @@ (** Ghost variables for YAML witnesses. *) let enabled () = - YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type + (YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type module Var = WitnessGhostVar @@ -24,3 +24,23 @@ let update_entry ~task ~node x e = let variable = name_varinfo x in let expression = CilType.Exp.show e in YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression + +let variable' x = + let variable = name_varinfo x in + let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) + let initial = CilType.Exp.show (initial x) in + YamlWitness.Entry.ghost_variable' ~variable ~type_ ~initial + +let update' x e = + let variable = name_varinfo x in + let expression = CilType.Exp.show e in + YamlWitness.Entry.ghost_update' ~variable ~expression + +let location_update' ~node ~updates = + let loc = Node.location node in + let location_function = (Node.find_fundec node).svar.vname in + let location = YamlWitness.Entry.location ~location:loc ~location_function in + YamlWitness.Entry.ghost_location_update' ~location ~updates + +let instrumentation_entry ~task ~variables ~location_updates = + YamlWitness.Entry.ghost_instrumentation ~task ~variables ~location_updates diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 8999d394ec..eec046bcb6 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -148,6 +148,93 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm unsafe: 0 total memory locations: 1 +Same with ghost_instrumentation entry. + + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c + [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) + [Warning][Deadcode] Function 'producer' has dead code: + on line 26 (74-mutex.c:26-26) + [Warning][Deadcode] Logical lines of code (LLoC) summary: + live: 14 + dead: 1 + total lines: 15 + [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) + [Info][Witness] witness generation summary: + total generation entries: 3 + [Info][Race] Memory locations race summary: + safe: 1 + vulnerable: 0 + unsafe: 0 + total memory locations: 1 + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_instrumentation + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: "0" + - name: m_locked + scope: global + type: int + initial: "0" + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - ghost_variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - ghost_variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - ghost_variable: multithreaded + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - ghost_variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - ghost_variable: m_locked + expression: "1" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m_locked || used == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= used && used <= 1)' + type: assertion + format: C + Same with mutex-meet. $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c From f79ad180cc9bb3ff2b00b73fcda4368718b8f307 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:53:28 +0300 Subject: [PATCH 083/103] Add option for emitting flow_insensitive_invariant-s as invariant_set location_invariant-s in YAML witnesses --- conf/svcomp-ghost.json | 2 +- src/config/options.schema.json | 9 ++-- src/witness/yamlWitness.ml | 52 ++++++++++++++++--- .../regression/13-privatized/04-priv_multi.t | 2 +- tests/regression/13-privatized/74-mutex.t | 40 +++++++++----- 5 files changed, 77 insertions(+), 28 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index ce308c5e52..c4f165960d 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -150,7 +150,7 @@ "accessed": false, "exact": true, "all-locals": false, - "flow_insensitive-as-location": true, + "flow_insensitive-as": "location_invariant", "exclude-vars": [ "tmp\\(___[0-9]+\\)?", "cond", diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 06b6f26359..11df177cd3 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2604,11 +2604,12 @@ "type": "boolean", "default": true }, - "flow_insensitive-as-location": { - "title": "witness.invariant.flow_insensitive-as-location", + "flow_insensitive-as": { + "title": "witness.invariant.flow_insensitive-as", "description": "Emit flow-insensitive invariants as location invariants at certain locations.", - "type": "boolean", - "default": false + "type": "string", + "enum": ["flow_insensitive_invariant", "location_invariant", "invariant_set-location_invariant"], + "default": "flow_insensitive_invariant" } }, "additionalProperties": false diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index cc435a38ac..c8217bde19 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -347,22 +347,23 @@ struct entries in + let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in + (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( - let ns = lazy (R.ask_global InvariantGlobalNodes) in GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) - begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_bool "witness.invariant.flow_insensitive-as-location" with - | `Lifted inv, false -> + begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_string "witness.invariant.flow_insensitive-as" with + | `Lifted inv, "flow_insensitive_invariant" -> let invs = WitnessUtil.InvariantExp.process_exp inv in List.fold_left (fun acc inv -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.flow_insensitive_invariant ~task ~invariant in entry :: acc ) acc invs - | `Lifted inv, true -> + | `Lifted inv, "location_invariant" -> (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> @@ -377,7 +378,8 @@ struct entry :: acc ) acc invs | None -> acc - ) (Lazy.force ns) acc + ) (Lazy.force invariant_global_nodes) acc + | `Lifted _, _ | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end @@ -516,12 +518,12 @@ struct (* Generate invariant set *) let entries = - if entry_type_enabled YamlWitnessType.InvariantSet.entry_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type || entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( let invariants = [] in (* Generate location invariants *) let invariants = - if invariant_type_enabled YamlWitnessType.InvariantSet.LocationInvariant.invariant_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type && invariant_type_enabled YamlWitnessType.InvariantSet.LocationInvariant.invariant_type then ( LH.fold (fun loc ns acc -> let inv = List.fold_left (fun acc n -> let local = try NH.find (Lazy.force nh) n with Not_found -> Spec.D.bot () in @@ -550,7 +552,7 @@ struct (* Generate loop invariants *) let invariants = - if invariant_type_enabled YamlWitnessType.InvariantSet.LoopInvariant.invariant_type then ( + if entry_type_enabled YamlWitnessType.InvariantSet.entry_type && invariant_type_enabled YamlWitnessType.InvariantSet.LoopInvariant.invariant_type then ( LH.fold (fun loc ns acc -> if WitnessInvariant.emit_loop_head then ( (* TODO: remove double condition? *) let inv = List.fold_left (fun acc n -> @@ -580,6 +582,40 @@ struct invariants in + (* Generate flow-insensitive invariants as location invariants *) + let invariants = + if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( + GHT.fold (fun g v acc -> + match g with + | `Left g -> (* Spec global *) + begin match R.ask_global (InvariantGlobal (Obj.repr g)) with + | `Lifted inv -> + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + let invariant = CilType.Exp.show inv in + let invariant = Entry.location_invariant' ~location ~invariant in + invariant :: acc + ) acc invs + | None -> acc + ) (Lazy.force invariant_global_nodes) acc + | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) + acc + end + | `Right _ -> (* contexts global *) + acc + ) gh invariants + ) + else + invariants + in + let invariants = List.rev invariants in let entry = Entry.invariant_set ~task ~invariants in entry :: entries diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index b1a45dd917..fd0dad6a39 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -174,7 +174,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index eec046bcb6..c99cdb6ff9 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -84,7 +84,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --enable witness.invariant.flow_insensitive-as-location 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -148,9 +148,9 @@ Earlyglobs shouldn't cause protected writes in multithreaded mode from being imm unsafe: 0 total memory locations: 1 -Same with ghost_instrumentation entry. +Same with ghost_instrumentation and invariant_set entries. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as invariant_set-location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -160,7 +160,7 @@ Same with ghost_instrumentation entry. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -224,16 +224,28 @@ Same with ghost_instrumentation entry. updates: - ghost_variable: m_locked expression: "1" - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (m_locked || used == 0)' - type: assertion - format: C - - entry_type: flow_insensitive_invariant - flow_insensitive_invariant: - string: '! multithreaded || (0 <= used && used <= 1)' - type: assertion - format: C + - entry_type: invariant_set + content: + - invariant: + type: location_invariant + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + value: '! multithreaded || (m_locked || used == 0)' + format: c_expression + - invariant: + type: location_invariant + location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + value: '! multithreaded || (0 <= used && used <= 1)' + format: c_expression Same with mutex-meet. From e9e652d86cac07bdff43780fbe5467fe46870265 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 12:56:26 +0300 Subject: [PATCH 084/103] Use invariant_set in svcomp-ghost conf --- conf/svcomp-ghost.json | 7 +++---- src/config/options.schema.json | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/conf/svcomp-ghost.json b/conf/svcomp-ghost.json index c4f165960d..cb4d8f1384 100644 --- a/conf/svcomp-ghost.json +++ b/conf/svcomp-ghost.json @@ -136,11 +136,10 @@ }, "yaml": { "enabled": true, - "format-version": "0.1", + "format-version": "2.1", "entry-types": [ "flow_insensitive_invariant", - "ghost_variable", - "ghost_update" + "ghost_instrumentation" ] }, "invariant": { @@ -150,7 +149,7 @@ "accessed": false, "exact": true, "all-locals": false, - "flow_insensitive-as": "location_invariant", + "flow_insensitive-as": "invariant_set-location_invariant", "exclude-vars": [ "tmp\\(___[0-9]+\\)?", "cond", diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 11df177cd3..1101e04ace 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2630,7 +2630,8 @@ "type": "string", "enum": [ "0.1", - "2.0" + "2.0", + "2.1" ], "default": "0.1" }, From 431b34d18d12ef588c67a170f4a139665e73720c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Tue, 20 Aug 2024 15:02:07 +0300 Subject: [PATCH 085/103] Make invariant_set and ghost_instrumentation deterministic in tests --- tests/regression/13-privatized/74-mutex.t | 40 +++++++++++------------ tests/util/yamlWitnessStrip.ml | 12 +++++-- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index c99cdb6ff9..0c2947ab37 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -170,11 +170,11 @@ Same with ghost_instrumentation and invariant_set entries. $ yamlWitnessStrip < witness.yml - entry_type: ghost_instrumentation ghost_variables: - - name: multithreaded + - name: m_locked scope: global type: int initial: "0" - - name: m_locked + - name: multithreaded scope: global type: int initial: "0" @@ -182,21 +182,21 @@ Same with ghost_instrumentation and invariant_set entries. - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 38 - column: 3 - function: main + line: 20 + column: 5 + function: producer updates: - ghost_variable: m_locked - expression: "0" + expression: "1" - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 36 - column: 3 - function: main + line: 23 + column: 5 + function: producer updates: - ghost_variable: m_locked - expression: "1" + expression: "0" - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -209,21 +209,21 @@ Same with ghost_instrumentation and invariant_set entries. - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer + line: 36 + column: 3 + function: main updates: - ghost_variable: m_locked - expression: "0" + expression: "1" - location: file_name: 74-mutex.c file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer + line: 38 + column: 3 + function: main updates: - ghost_variable: m_locked - expression: "1" + expression: "0" - entry_type: invariant_set content: - invariant: @@ -234,7 +234,7 @@ Same with ghost_instrumentation and invariant_set entries. line: 36 column: 3 function: main - value: '! multithreaded || (m_locked || used == 0)' + value: '! multithreaded || (0 <= used && used <= 1)' format: c_expression - invariant: type: location_invariant @@ -244,7 +244,7 @@ Same with ghost_instrumentation and invariant_set entries. line: 36 column: 3 function: main - value: '! multithreaded || (0 <= used && used <= 1)' + value: '! multithreaded || (m_locked || used == 0)' format: c_expression Same with mutex-meet. diff --git a/tests/util/yamlWitnessStrip.ml b/tests/util/yamlWitnessStrip.ml index 4d7b446bab..dff8bfb0cf 100644 --- a/tests/util/yamlWitnessStrip.ml +++ b/tests/util/yamlWitnessStrip.ml @@ -27,7 +27,10 @@ struct {invariant_type} in let ghost_location_update_strip_file_hash (x: GhostInstrumentation.LocationUpdate.t): GhostInstrumentation.LocationUpdate.t = - {x with location = location_strip_file_hash x.location} + { + location = location_strip_file_hash x.location; + updates = List.sort GhostInstrumentation.Update.compare x.updates + } in let entry_type: EntryType.t = match entry_type with @@ -44,13 +47,16 @@ struct | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate {x with target = target_strip_file_hash x.target} | InvariantSet x -> - InvariantSet {content = List.map invariant_strip_file_hash x.content} + InvariantSet {content = List.sort InvariantSet.Invariant.compare (List.map invariant_strip_file_hash x.content)} (* Sort, so order is deterministic regardless of Goblint. *) | GhostVariable x -> GhostVariable x (* no location to strip *) | GhostUpdate x -> GhostUpdate {x with location = location_strip_file_hash x.location} | GhostInstrumentation x -> - GhostInstrumentation {x with ghost_updates = List.map ghost_location_update_strip_file_hash x.ghost_updates} + GhostInstrumentation { (* Sort, so order is deterministic regardless of Goblint. *) + ghost_variables = List.sort GhostInstrumentation.Variable.compare x.ghost_variables; + ghost_updates = List.sort GhostInstrumentation.LocationUpdate.compare (List.map ghost_location_update_strip_file_hash x.ghost_updates); + } in {entry_type} From 2c9955048a13c162fcf74f7ccd67d614c73e3ee5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Wed, 28 Aug 2024 17:25:23 +0300 Subject: [PATCH 086/103] Remove ghost_ prefix from ghost_instrumentation update entries --- src/witness/yamlWitness.ml | 2 +- src/witness/yamlWitnessType.ml | 10 +++++----- tests/regression/13-privatized/74-mutex.t | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index c8217bde19..c917361d9b 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -169,7 +169,7 @@ struct } let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { - ghost_variable = variable; + variable; expression; } diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 72afbf432b..cefb0866f3 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -518,22 +518,22 @@ struct module Update = struct type t = { - ghost_variable: string; + variable: string; expression: string; } [@@deriving eq, ord, hash] - let to_yaml {ghost_variable; expression} = + let to_yaml {variable; expression} = `O [ - ("ghost_variable", `String ghost_variable); + ("variable", `String variable); ("expression", `String expression); ] let of_yaml y = let open GobYaml in - let+ ghost_variable = y |> find "ghost_variable" >>= to_string + let+ variable = y |> find "variable" >>= to_string and+ expression = y |> find "expression" >>= to_string in - {ghost_variable; expression} + {variable; expression} end module LocationUpdate = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 0c2947ab37..9a11b6846f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -186,7 +186,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 5 function: producer updates: - - ghost_variable: m_locked + - variable: m_locked expression: "1" - location: file_name: 74-mutex.c @@ -195,7 +195,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 5 function: producer updates: - - ghost_variable: m_locked + - variable: m_locked expression: "0" - location: file_name: 74-mutex.c @@ -204,7 +204,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: multithreaded + - variable: multithreaded expression: "1" - location: file_name: 74-mutex.c @@ -213,7 +213,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: m_locked + - variable: m_locked expression: "1" - location: file_name: 74-mutex.c @@ -222,7 +222,7 @@ Same with ghost_instrumentation and invariant_set entries. column: 3 function: main updates: - - ghost_variable: m_locked + - variable: m_locked expression: "0" - entry_type: invariant_set content: From 12dadf4f03c8ff9d3e4a1546235722066018fd40 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 2 Sep 2024 11:03:57 +0300 Subject: [PATCH 087/103] Wrap ghost_instrumentation in content --- src/witness/yamlWitnessType.ml | 13 ++- tests/regression/13-privatized/74-mutex.t | 111 +++++++++++----------- 2 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index cefb0866f3..b04a2c35bf 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -566,15 +566,18 @@ struct let entry_type = "ghost_instrumentation" let to_yaml' {ghost_variables; ghost_updates} = - [ - ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); - ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + [("content", + `O [ + ("ghost_variables", `A (List.map Variable.to_yaml ghost_variables)); + ("ghost_updates", `A (List.map LocationUpdate.to_yaml ghost_updates)); + ]) ] let of_yaml y = let open GobYaml in - let+ ghost_variables = y |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml - and+ ghost_updates = y |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in + let* content = y |> find "content" in + let+ ghost_variables = content |> find "ghost_variables" >>= list >>= list_map Variable.of_yaml + and+ ghost_updates = content |> find "ghost_updates" >>= list >>= list_map LocationUpdate.of_yaml in {ghost_variables; ghost_updates} end diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 9a11b6846f..478921155e 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -169,61 +169,62 @@ Same with ghost_instrumentation and invariant_set entries. $ yamlWitnessStrip < witness.yml - entry_type: ghost_instrumentation - ghost_variables: - - name: m_locked - scope: global - type: int - initial: "0" - - name: multithreaded - scope: global - type: int - initial: "0" - ghost_updates: - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - updates: - - variable: m_locked - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - updates: - - variable: m_locked - expression: "0" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - updates: - - variable: multithreaded - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - updates: - - variable: m_locked - expression: "1" - - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - updates: - - variable: m_locked - expression: "0" + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: "0" + - name: multithreaded + scope: global + type: int + initial: "0" + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + expression: "0" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + expression: "1" + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + expression: "0" - entry_type: invariant_set content: - invariant: From 852297b68abbcb05c3f3700098e2bc2f22c93333 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Mon, 2 Sep 2024 11:10:31 +0300 Subject: [PATCH 088/103] Add value and format to ghost_instrumentation --- src/witness/yamlWitness.ml | 8 +++-- src/witness/yamlWitnessType.ml | 40 ++++++++++++++++++----- tests/regression/13-privatized/74-mutex.t | 23 +++++++++---- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index c917361d9b..f8890d8eaa 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -165,12 +165,16 @@ struct name = variable; scope = "global"; type_; - initial; + initial = { + value = initial; + format = "c_expression"; + }; } let ghost_update' ~variable ~(expression): GhostInstrumentation.Update.t = { variable; - expression; + value = expression; + format = "c_expression"; } let ghost_location_update' ~location ~(updates): GhostInstrumentation.LocationUpdate.t = { diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index b04a2c35bf..7834951892 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -488,13 +488,34 @@ end module GhostInstrumentation = struct + module Initial = + struct + type t = { + value: string; + format: string; + } + [@@deriving eq, ord, hash] + + let to_yaml {value; format} = + `O [ + ("value", `String value); + ("format", `String format); + ] + + let of_yaml y = + let open GobYaml in + let+ value = y |> find "value" >>= to_string + and+ format = y |> find "format" >>= to_string in + {value; format} + end + module Variable = struct type t = { name: string; scope: string; type_: string; - initial: string; + initial: Initial.t; } [@@deriving eq, ord, hash] @@ -503,7 +524,7 @@ struct ("name", `String name); ("scope", `String scope); ("type", `String type_); - ("initial", `String initial); + ("initial", Initial.to_yaml initial); ] let of_yaml y = @@ -511,7 +532,7 @@ struct let+ name = y |> find "name" >>= to_string and+ scope = y |> find "scope" >>= to_string and+ type_ = y |> find "type" >>= to_string - and+ initial = y |> find "initial" >>= to_string in + and+ initial = y |> find "initial" >>= Initial.of_yaml in {name; scope; type_; initial} end @@ -519,21 +540,24 @@ struct struct type t = { variable: string; - expression: string; + value: string; + format: string; } [@@deriving eq, ord, hash] - let to_yaml {variable; expression} = + let to_yaml {variable; value; format} = `O [ ("variable", `String variable); - ("expression", `String expression); + ("value", `String value); + ("format", `String format); ] let of_yaml y = let open GobYaml in let+ variable = y |> find "variable" >>= to_string - and+ expression = y |> find "expression" >>= to_string in - {variable; expression} + and+ value = y |> find "value" >>= to_string + and+ format = y |> find "format" >>= to_string in + {variable; value; format} end module LocationUpdate = diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 478921155e..8a1a7fee5f 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -174,11 +174,15 @@ Same with ghost_instrumentation and invariant_set entries. - name: m_locked scope: global type: int - initial: "0" + initial: + value: "0" + format: c_expression - name: multithreaded scope: global type: int - initial: "0" + initial: + value: "0" + format: c_expression ghost_updates: - location: file_name: 74-mutex.c @@ -188,7 +192,8 @@ Same with ghost_instrumentation and invariant_set entries. function: producer updates: - variable: m_locked - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -197,7 +202,8 @@ Same with ghost_instrumentation and invariant_set entries. function: producer updates: - variable: m_locked - expression: "0" + value: "0" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -206,7 +212,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: multithreaded - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -215,7 +222,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: m_locked - expression: "1" + value: "1" + format: c_expression - location: file_name: 74-mutex.c file_hash: $FILE_HASH @@ -224,7 +232,8 @@ Same with ghost_instrumentation and invariant_set entries. function: main updates: - variable: m_locked - expression: "0" + value: "0" + format: c_expression - entry_type: invariant_set content: - invariant: From ced56ca4882ae5c461d1a7aefd435e814283c02a Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:06:41 +0200 Subject: [PATCH 089/103] Document YamlEntryGlobal and InvariantGlobalNodes queries --- src/domains/queries.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/domains/queries.ml b/src/domains/queries.ml index 5436e5f7e0..e3a0a3e776 100644 --- a/src/domains/queries.ml +++ b/src/domains/queries.ml @@ -131,9 +131,9 @@ type _ t = | TmpSpecial: Mval.Exp.t -> ML.t t | MaySignedOverflow: exp -> MayBool.t t | GasExhausted: MustBool.t t - | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t + | YamlEntryGlobal: Obj.t * YamlWitnessType.Task.t -> YS.t t (** YAML witness entries for a global unknown ([Obj.t] represents [Spec.V.t]) and YAML witness task. *) | GhostVarAvailable: WitnessGhostVar.t -> MayBool.t t - | InvariantGlobalNodes: NS.t t (* TODO: V.t argument? *) + | InvariantGlobalNodes: NS.t t (** Nodes where YAML witness flow-insensitive invariants should be emitted as location invariants (if [witness.invariant.flow_insensitive-as] is configured to do so). *) (* [Spec.V.t] argument (as [Obj.t]) could be added, if this should be different for different flow-insensitive invariants. *) type 'a result = 'a From 969b87a02e7e956beb8911dc753c42918510a48d Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:10:38 +0200 Subject: [PATCH 090/103] Replace privatization invariant_global mutex_inits TODO with comment --- src/analyses/apron/relationPriv.apron.ml | 2 +- src/analyses/basePriv.ml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index 9b25abb371..abaaa0d9b8 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -722,7 +722,7 @@ struct let one_var = GobConfig.get_bool "ana.relation.invariant.one-var" in let exact = GobConfig.get_bool "witness.invariant.exact" in - let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* TODO: disjunct with mutex_inits instead of join? *) + let rel = keep_only_protected_globals ask m' (get_m_with_mutex_inits ask getg m') in (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) let inv = RD.invariant rel |> List.enum diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 347a365778..7a67d0e0fc 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -250,7 +250,7 @@ struct let invariant_global ask getg = function | `Right g' -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g' (* TODO: disjunct with mutex_inits instead of join? *) + ValueDomain.invariant_global (read_unprotected_global getg) g' (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) | _ -> (* mutex *) Invariant.none @@ -343,7 +343,7 @@ struct | `Left m' -> (* mutex *) let atomic = LockDomain.MustLock.equal m' (LockDomain.MustLock.of_var LibraryFunctions.verifier_atomic_var) in if atomic || ask.f (GhostVarAvailable (Locked m')) then ( - let cpa = get_m_with_mutex_inits ask getg m' in (* TODO: disjunct with mutex_inits instead of join? *) + let cpa = get_m_with_mutex_inits ask getg m' in (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) let inv = CPA.fold (fun v _ acc -> if ask.f (MustBeProtectedBy {mutex = m'; global = v; write = true; protection = Strong}) then let inv = ValueDomain.invariant_global (fun g -> CPA.find g cpa) v in @@ -704,7 +704,7 @@ struct let invariant_global ask getg = function | `Middle g -> (* global *) - ValueDomain.invariant_global (read_unprotected_global getg) g (* TODO: disjunct with mutex_inits instead of join? *) + ValueDomain.invariant_global (read_unprotected_global getg) g (* Could be more precise if mutex_inits invariant is added by disjunction instead of joining abstract values. *) | `Left _ | `Right _ -> (* mutex or thread *) Invariant.none From 4940658a23799a16f78731570ca9921ff8f2b0f2 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:15:27 +0200 Subject: [PATCH 091/103] Apply suggestions from code review Co-authored-by: Julian Erhard --- src/analyses/mutexGhosts.ml | 1 - src/witness/witnessGhostVar.ml | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 09afc41baa..87e7281028 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -10,7 +10,6 @@ struct include UnitAnalysis.Spec let name () = "mutexGhosts" - (* module ThreadCreate = Printable.UnitConf (struct let name = "threadcreate" end) *) module V = struct include Printable.Either3 (Node) (LockDomain.MustLock) (BoolDomain.Bool) diff --git a/src/witness/witnessGhostVar.ml b/src/witness/witnessGhostVar.ml index 82813b4a65..0d71909ba0 100644 --- a/src/witness/witnessGhostVar.ml +++ b/src/witness/witnessGhostVar.ml @@ -35,9 +35,9 @@ include Printable.SimpleShow (struct let describe_varinfo _ _ = "" let typ = function - | Locked _ -> GoblintCil.intType + | Locked _ | Multithreaded -> GoblintCil.intType let initial = function - | Locked _ -> GoblintCil.zero + | Locked _ | Multithreaded -> GoblintCil.zero From 09045bc232f7cf0e36389534eb3fc5e56e1d81d7 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:32:17 +0200 Subject: [PATCH 092/103] Add nontrivial condition for querying YamlEntryGlobal at all --- src/witness/yamlWitness.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index f8890d8eaa..ec83fa04fb 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -397,7 +397,7 @@ struct (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = - if true then ( + if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( GHT.fold (fun g v acc -> match g with | `Left g -> (* Spec global *) From 3a07c1615d9a4888a0e972fc6da69719d91e9fb6 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:47:07 +0200 Subject: [PATCH 093/103] Remove old unnecessary branching from ghost_update YAML witness entries --- src/witness/yamlWitnessType.ml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 7834951892..fa2d55d2c2 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -464,7 +464,6 @@ struct variable: string; expression: string; location: Location.t; - (* TODO: branching? *) } [@@deriving eq, ord, hash] From 9a3a338287664b9697bf2eaa0eca378bd5be247b Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 10:53:46 +0200 Subject: [PATCH 094/103] Implement YamlWitnessType.Entry pretty-printing --- src/witness/yamlWitnessType.ml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index fa2d55d2c2..6ec133c7d6 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -693,12 +693,6 @@ struct let name () = "YAML entry" - let show _ = "TODO" - include Printable.SimpleShow (struct - type nonrec t = t - let show = show - end) - let to_yaml {entry_type; metadata} = `O ([ ("entry_type", `String (EntryType.entry_type entry_type)); @@ -710,4 +704,10 @@ struct let+ metadata = y |> find "metadata" >>= Metadata.of_yaml and+ entry_type = y |> EntryType.of_yaml in {entry_type; metadata} + + let pp ppf x = Yaml.pp ppf (to_yaml x) + include Printable.SimpleFormat (struct + type nonrec t = t + let pp = pp + end) end From 34277e041b43c093d2d635a586e10686c35a3f8e Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 11:24:42 +0200 Subject: [PATCH 095/103] Use sets instead of BatList.mem_cmp for deduplicating ghost witness variables --- src/analyses/mutexGhosts.ml | 19 ++++++------------- src/witness/yamlWitness.ml | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 87e7281028..6542ab3607 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -114,6 +114,8 @@ struct let ghost_var_available ctx v = WitnessGhost.enabled () && ghost_var_available ctx v + module VariableSet = Set.Make (YamlWitnessType.GhostInstrumentation.Variable) + let query ctx (type a) (q: a Queries.t): a Queries.result = match q with | GhostVarAvailable v -> ghost_var_available ctx v @@ -173,15 +175,11 @@ struct let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> let (locked, unlocked, multithread) = G.node (ctx.global (V.node node)) in let variables' = - (* TODO: do variable_entry-s only once *) Locked.fold (fun l acc -> match mustlock_of_addr l with | Some l when ghost_var_available ctx (Locked l) -> let variable = WitnessGhost.variable' (Locked l) in - if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable acc then (* TODO: be efficient *) - acc - else - variable :: acc + VariableSet.add variable acc | _ -> acc ) (Locked.union locked unlocked) variables @@ -211,12 +209,7 @@ struct if ghost_var_available ctx Multithreaded then ( let variable = WitnessGhost.variable' Multithreaded in let update = WitnessGhost.update' Multithreaded GoblintCil.one in - let variables' = - if BatList.mem_cmp YamlWitnessType.GhostInstrumentation.Variable.compare variable variables' then (* TODO: be efficient *) - variables' - else - variable :: variables' - in + let variables' = VariableSet.add variable variables' in (variables', update :: updates) ) else @@ -227,9 +220,9 @@ struct in let location_update = WitnessGhost.location_update' ~node ~updates in (variables', location_update :: location_updates) - ) nodes ([], []) + ) nodes (VariableSet.empty, []) in - let entry = WitnessGhost.instrumentation_entry ~task ~variables ~location_updates in + let entry = WitnessGhost.instrumentation_entry ~task ~variables:(VariableSet.elements variables) ~location_updates in Queries.YS.singleton entry | `Left _ -> Queries.Result.top q | `Middle _ -> Queries.Result.top q diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index ec83fa04fb..a044750a79 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -398,23 +398,24 @@ struct (* Generate flow-insensitive entries (ghost variables and ghost updates) *) let entries = if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( - GHT.fold (fun g v acc -> + let module EntrySet = Queries.YS in + fst @@ GHT.fold (fun g v accs -> match g with | `Left g -> (* Spec global *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> - Queries.YS.fold (fun entry acc -> - if BatList.mem_cmp YamlWitnessType.Entry.compare entry acc then (* TODO: be efficient *) - acc + Queries.YS.fold (fun entry (acc, acc') -> + if EntrySet.mem entry acc' then (* deduplicate only with other global entries because local ones have different locations anyway *) + accs else - entry :: acc - ) inv acc + (entry :: acc, EntrySet.add entry acc') + ) inv accs | `Top -> - acc + accs end | `Right _ -> (* contexts global *) - acc - ) gh entries + accs + ) gh (entries, EntrySet.empty ()) ) else entries From 7929d633ee5dc3e30c3607596850bcb64995352f Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 11:48:58 +0200 Subject: [PATCH 096/103] Extract fold_flow_insensitive_as_location in YamlWitness to deduplicate code --- src/witness/yamlWitness.ml | 56 ++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index a044750a79..b0ffac5852 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -353,6 +353,22 @@ struct let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in + let fold_flow_insensitive_as_location ~inv f acc = + (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + let invs = WitnessUtil.InvariantExp.process_exp inv in + Queries.NS.fold (fun n acc -> + let fundec = Node.find_fundec n in + match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + | Some loc -> + let location_function = fundec.svar.vname in + let location = Entry.location ~location:loc ~location_function in + List.fold_left (fun acc inv -> + f ~location ~inv acc + ) acc invs + | None -> acc + ) (Lazy.force invariant_global_nodes) acc + in + (* Generate flow-insensitive invariants *) let entries = if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( @@ -368,21 +384,11 @@ struct entry :: acc ) acc invs | `Lifted inv, "location_invariant" -> - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) - let invs = WitnessUtil.InvariantExp.process_exp inv in - Queries.NS.fold (fun n acc -> - let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) - | Some loc -> - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = Entry.invariant (CilType.Exp.show inv) in - let entry = Entry.location_invariant ~task ~location ~invariant in - entry :: acc - ) acc invs - | None -> acc - ) (Lazy.force invariant_global_nodes) acc + fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> + let invariant = Entry.invariant (CilType.Exp.show inv) in + let entry = Entry.location_invariant ~task ~location ~invariant in + entry :: acc + ) acc | `Lifted _, _ | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc @@ -595,21 +601,11 @@ struct | `Left g -> (* Spec global *) begin match R.ask_global (InvariantGlobal (Obj.repr g)) with | `Lifted inv -> - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) - let invs = WitnessUtil.InvariantExp.process_exp inv in - Queries.NS.fold (fun n acc -> - let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) - | Some loc -> - let location_function = fundec.svar.vname in - let location = Entry.location ~location:loc ~location_function in - List.fold_left (fun acc inv -> - let invariant = CilType.Exp.show inv in - let invariant = Entry.location_invariant' ~location ~invariant in - invariant :: acc - ) acc invs - | None -> acc - ) (Lazy.force invariant_global_nodes) acc + fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> + let invariant = CilType.Exp.show inv in + let invariant = Entry.location_invariant' ~location ~invariant in + invariant :: acc + ) acc | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end From 8a0240ddb8753ab6e40691c301550c602fe821cb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 12:08:02 +0200 Subject: [PATCH 097/103] Update ghost witness related TODOs and comments --- src/analyses/apron/relationPriv.apron.ml | 2 +- src/analyses/basePriv.ml | 2 +- src/witness/yamlWitness.ml | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/analyses/apron/relationPriv.apron.ml b/src/analyses/apron/relationPriv.apron.ml index abaaa0d9b8..02ebe4d0e6 100644 --- a/src/analyses/apron/relationPriv.apron.ml +++ b/src/analyses/apron/relationPriv.apron.ml @@ -747,7 +747,7 @@ struct else Invariant.none | g -> (* global *) - Invariant.none (* TODO: ? *) + Invariant.none (* Could output unprotected one-variable (so non-relational) invariants, but probably not very useful. [BasePriv] does those anyway. *) end (** May written variables. *) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index 7a67d0e0fc..c46492b7c7 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -891,7 +891,7 @@ struct else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: this takes protected values of everything *) + let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: This takes protected values of every [g], not just [g'], which might be unsound with pointers. See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. It should be possible to be more precise because writes only happen with all of them held, but conjunction is unsound when one of the mutexes is temporarily unlocked. diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index b0ffac5852..159892fd20 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -354,11 +354,13 @@ struct let invariant_global_nodes = lazy (R.ask_global InvariantGlobalNodes) in let fold_flow_insensitive_as_location ~inv f acc = - (* TODO: or do at location_invariant loop for each node and query if should also do global invariants there? *) + (* Currently same invariants (from InvariantGlobal query) for all nodes (from InvariantGlobalNodes query). + The alternative would be querying InvariantGlobal per local unknown when looping over them to generate location invariants. + See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698149514. *) let invs = WitnessUtil.InvariantExp.process_exp inv in Queries.NS.fold (fun n acc -> let fundec = Node.find_fundec n in - match WitnessInvariant.location_location n with (* if after thread create node happens to be loop node *) + match WitnessInvariant.location_location n with (* Not just using Node.location because it returns expression location which may be invalid for location invariant (e.g. inside conditional). *) | Some loc -> let location_function = fundec.svar.vname in let location = Entry.location ~location:loc ~location_function in @@ -374,7 +376,7 @@ struct if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type then ( GHT.fold (fun g v acc -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (InvariantGlobal (Obj.repr g)), GobConfig.get_string "witness.invariant.flow_insensitive-as" with | `Lifted inv, "flow_insensitive_invariant" -> let invs = WitnessUtil.InvariantExp.process_exp inv in @@ -393,7 +395,7 @@ struct | `Bot, _ | `Top, _ -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) acc ) gh entries ) @@ -407,7 +409,7 @@ struct let module EntrySet = Queries.YS in fst @@ GHT.fold (fun g v accs -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (YamlEntryGlobal (Obj.repr g, task)) with | `Lifted _ as inv -> Queries.YS.fold (fun entry (acc, acc') -> @@ -419,7 +421,7 @@ struct | `Top -> accs end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) accs ) gh (entries, EntrySet.empty ()) ) @@ -598,7 +600,7 @@ struct if entry_type_enabled YamlWitnessType.FlowInsensitiveInvariant.entry_type && GobConfig.get_string "witness.invariant.flow_insensitive-as" = "invariant_set-location_invariant" then ( GHT.fold (fun g v acc -> match g with - | `Left g -> (* Spec global *) + | `Left g -> (* global unknown from analysis Spec *) begin match R.ask_global (InvariantGlobal (Obj.repr g)) with | `Lifted inv -> fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> @@ -609,7 +611,7 @@ struct | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) acc end - | `Right _ -> (* contexts global *) + | `Right _ -> (* global unknown for FromSpec contexts *) acc ) gh invariants ) From 64c11c2748d2981346d909392423fde938c8ca8c Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:10:36 +0200 Subject: [PATCH 098/103] Add test 56-witness/69-ghost-ptr-protection for unsound protection flow-sensitive invariant --- .../56-witness/69-ghost-ptr-protection.c | 30 ++++++ .../56-witness/69-ghost-ptr-protection.t | 101 ++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 tests/regression/56-witness/69-ghost-ptr-protection.c create mode 100644 tests/regression/56-witness/69-ghost-ptr-protection.t diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.c b/tests/regression/56-witness/69-ghost-ptr-protection.c new file mode 100644 index 0000000000..f5557f3fc8 --- /dev/null +++ b/tests/regression/56-witness/69-ghost-ptr-protection.c @@ -0,0 +1,30 @@ +// PARAM: --set ana.activated[+] mutexGhosts +// CRAM +#include +#include + +int g = 0; +int *p = &g; +pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +void *t_fun(void *arg) { + int x = 10; + pthread_mutex_lock(&m2); + p = &x; + p = &g; + pthread_mutex_unlock(&m2); + return NULL; +} + +int main() { + pthread_t id; + pthread_create(&id, NULL, t_fun, NULL); + pthread_mutex_lock(&m1); + g = 1; + // m2_locked || (p == & g && *p == 0) would be violated here + __goblint_check(*p != 0); // 1 from g or 10 from x in t_fun + g = 0; + pthread_mutex_unlock(&m1); + return 0; +} diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t new file mode 100644 index 0000000000..03481a7ce1 --- /dev/null +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -0,0 +1,101 @@ + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 69-ghost-ptr-protection.c + [Success][Assert] Assertion "*p != 0" will succeed (69-ghost-ptr-protection.c:26:3-26:27) + [Info][Deadcode] Logical lines of code (LLoC) summary: + live: 15 + dead: 0 + total lines: 15 + [Warning][Race] Memory location p (race with conf. 110): (69-ghost-ptr-protection.c:7:5-7:12) + write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:14:3-14:9) + write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) + read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) + [Info][Witness] witness generation summary: + total generation entries: 12 + [Info][Race] Memory locations race summary: + safe: 2 + vulnerable: 0 + unsafe: 1 + total memory locations: 3 + +TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): + + $ yamlWitnessStrip < witness.yml + - entry_type: ghost_update + variable: multithreaded + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: main + - entry_type: ghost_update + variable: m2_locked + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m2_locked + expression: "0" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + - entry_type: ghost_update + variable: m1_locked + expression: "1" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + - entry_type: ghost_update + variable: m1_locked + expression: "0" + location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + - entry_type: ghost_variable + variable: multithreaded + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m2_locked + scope: global + type: int + initial: "0" + - entry_type: ghost_variable + variable: m1_locked + scope: global + type: int + initial: "0" + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m2_locked || (p == & g && *p == 0))' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (m1_locked || g == 0)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (0 <= g && g <= 1)' + type: assertion + format: C + - entry_type: flow_insensitive_invariant + flow_insensitive_invariant: + string: '! multithreaded || (*p == 10 || ((0 <= *p && *p <= 1) && p == & g))' + type: assertion + format: C From b4734c31753b328b74283f9f82351fd6e09979c9 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:22:33 +0200 Subject: [PATCH 099/103] Fix unsound ghost witness invariant in 56-witness/69-ghost-ptr-protection --- src/analyses/basePriv.ml | 5 ++++- tests/regression/56-witness/69-ghost-ptr-protection.t | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/analyses/basePriv.ml b/src/analyses/basePriv.ml index b7e32ceb94..3afd758daa 100644 --- a/src/analyses/basePriv.ml +++ b/src/analyses/basePriv.ml @@ -891,7 +891,10 @@ struct else if VD.equal (getg (V.protected g')) (getg (V.unprotected g')) then Invariant.none (* don't output protected invariant because it's the same as unprotected *) else ( - let inv = ValueDomain.invariant_global (fun g -> getg (V.protected g)) g' in (* TODO: This takes protected values of every [g], not just [g'], which might be unsound with pointers. See: https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) + (* Only read g' as protected, everything else (e.g. pointed to variables) may be unprotected. + See 56-witness/69-ghost-ptr-protection and https://github.com/goblint/analyzer/pull/1394#discussion_r1698136411. *) + let read_global g = getg (if CilType.Varinfo.equal g g' then V.protected g else V.unprotected g) in + let inv = ValueDomain.invariant_global read_global g' in (* Very conservative about multiple (write-)protecting mutexes: invariant is not claimed when any of them is held. It should be possible to be more precise because writes only happen with all of them held, but conjunction is unsound when one of the mutexes is temporarily unlocked. diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t index 03481a7ce1..698f643385 100644 --- a/tests/regression/56-witness/69-ghost-ptr-protection.t +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -16,7 +16,7 @@ unsafe: 1 total memory locations: 3 -TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): +Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): $ yamlWitnessStrip < witness.yml - entry_type: ghost_update @@ -81,7 +81,7 @@ TODO: Should not contain unsound flow-insensitive invariant m2_locked || (p == & initial: "0" - entry_type: flow_insensitive_invariant flow_insensitive_invariant: - string: '! multithreaded || (m2_locked || (p == & g && *p == 0))' + string: '! multithreaded || (m2_locked || ((0 <= *p && *p <= 1) && p == & g))' type: assertion format: C - entry_type: flow_insensitive_invariant From d2e71cbbf773205abb600fc15cf07ba712a2e6eb Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 16:58:43 +0200 Subject: [PATCH 100/103] Change ghost witness tests to use ghost_instrumentation --- .../regression/13-privatized/04-priv_multi.t | 298 +++---- tests/regression/13-privatized/25-struct_nr.t | 125 +-- tests/regression/13-privatized/74-mutex.t | 258 +++--- tests/regression/13-privatized/92-idx_priv.t | 66 +- tests/regression/29-svcomp/16-atomic_priv.t | 76 +- .../regression/36-apron/12-traces-min-rpb1.t | 163 ++-- .../56-witness/64-ghost-multiple-protecting.t | 750 ++++++++++-------- .../56-witness/65-ghost-ambiguous-lock.t | 94 ++- .../56-witness/66-ghost-alloc-lock.t | 212 ++--- .../56-witness/67-ghost-no-unlock.t | 106 +-- .../56-witness/68-ghost-ambiguous-idx.t | 66 +- .../56-witness/69-ghost-ptr-protection.t | 136 ++-- 12 files changed, 1325 insertions(+), 1025 deletions(-) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index fd0dad6a39..3ea9b385fc 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -16,7 +16,7 @@ [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - total generation entries: 19 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -24,138 +24,158 @@ total memory locations: 2 $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 69 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 46 - column: 5 - function: dispose - - entry_type: ghost_update - variable: mutex_B_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 29 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 73 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 49 - column: 7 - function: dispose - - entry_type: ghost_update - variable: mutex_B_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 32 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 68 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 26 - column: 5 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 15 - column: 5 - function: generate - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 74 - column: 5 - function: main - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 34 - column: 7 - function: process - - entry_type: ghost_update - variable: mutex_A_locked - expression: "0" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 18 - column: 5 - function: generate - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 04-priv_multi.c - file_hash: $FILE_HASH - line: 63 - column: 3 - function: main - - entry_type: ghost_variable - variable: mutex_B_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: mutex_A_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: mutex_A_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: mutex_B_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 15 + column: 5 + function: generate + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 18 + column: 5 + function: generate + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 26 + column: 5 + function: process + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 29 + column: 7 + function: process + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 32 + column: 7 + function: process + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 34 + column: 7 + function: process + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 46 + column: 5 + function: dispose + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 49 + column: 7 + function: dispose + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 63 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 68 + column: 5 + function: main + updates: + - variable: mutex_A_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 69 + column: 5 + function: main + updates: + - variable: mutex_B_locked + value: "1" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 73 + column: 5 + function: main + updates: + - variable: mutex_B_locked + value: "0" + format: c_expression + - location: + file_name: 04-priv_multi.c + file_hash: $FILE_HASH + line: 74 + column: 5 + function: main + updates: + - variable: mutex_A_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (mutex_B_locked || (mutex_A_locked || B == 5))' @@ -174,7 +194,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as location_invariant 04-priv_multi.c [Success][Assert] Assertion "p == 5" will succeed (04-priv_multi.c:50:7-50:30) [Success][Assert] Assertion "A == B" will succeed (04-priv_multi.c:71:5-71:28) [Warning][Deadcode] Function 'dispose' has dead code: @@ -192,7 +212,7 @@ Flow-insensitive invariants as location invariants. [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - total generation entries: 25 + total generation entries: 10 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -204,7 +224,7 @@ Flow-insensitive invariants as location invariants. Location invariant at `for` loop in `main` should be on column 3, not 7. $ diff witness.flow_insensitive.yml witness.location.yml - 133,134c133,140 + 153,154c153,160 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -216,7 +236,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > column: 3 > function: main > location_invariant: - 138,139c144,151 + 158,159c164,171 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -228,7 +248,7 @@ Location invariant at `for` loop in `main` should be on column 3, not 7. > column: 3 > function: main > location_invariant: - 143,144c155,228 + 163,164c175,248 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- diff --git a/tests/regression/13-privatized/25-struct_nr.t b/tests/regression/13-privatized/25-struct_nr.t index 88f205a431..59ed9960f2 100644 --- a/tests/regression/13-privatized/25-struct_nr.t +++ b/tests/regression/13-privatized/25-struct_nr.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 25-struct_nr.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 25-struct_nr.c [Success][Assert] Assertion "glob1 == 5" will succeed (25-struct_nr.c:26:3-26:30) [Success][Assert] Assertion "t == 5" will succeed (25-struct_nr.c:16:3-16:26) [Success][Assert] Assertion "glob1 == -10" will succeed (25-struct_nr.c:18:3-18:32) @@ -8,7 +8,7 @@ dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -16,61 +16,72 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 27 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "1" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "0" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 32 - column: 3 - function: main - - entry_type: ghost_update - variable: lock1_mutex_locked - expression: "0" - location: - file_name: 25-struct_nr.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: lock1_mutex_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: lock1_mutex_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: lock1_mutex_locked + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: lock1_mutex_locked + value: "0" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 27 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: lock1_mutex_locked + value: "1" + format: c_expression + - location: + file_name: 25-struct_nr.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + updates: + - variable: lock1_mutex_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (lock1_mutex_locked || glob1 == 5)' diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 8a1a7fee5f..1c1f0c12be 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -8,7 +8,7 @@ total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -16,61 +16,72 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml | tee witness.flow_insensitive.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + value: "0" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m_locked || used == 0)' @@ -84,7 +95,7 @@ Flow-insensitive invariants as location invariants. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' --set witness.invariant.flow_insensitive-as location_invariant 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -94,7 +105,7 @@ Flow-insensitive invariants as location invariants. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -104,7 +115,7 @@ Flow-insensitive invariants as location invariants. $ yamlWitnessStrip < witness.yml > witness.location.yml $ diff witness.flow_insensitive.yml witness.location.yml - 56,57c56,63 + 67,68c67,74 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -116,7 +127,7 @@ Flow-insensitive invariants as location invariants. > column: 3 > function: main > location_invariant: - 61,62c67,74 + 72,73c78,85 < - entry_type: flow_insensitive_invariant < flow_insensitive_invariant: --- @@ -259,7 +270,7 @@ Same with ghost_instrumentation and invariant_set entries. Same with mutex-meet. - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 74-mutex.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 74-mutex.c [Success][Assert] Assertion "used == 0" will succeed (74-mutex.c:37:3-37:29) [Warning][Deadcode] Function 'producer' has dead code: on line 26 (74-mutex.c:26-26) @@ -269,7 +280,7 @@ Same with mutex-meet. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - total generation entries: 9 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -277,61 +288,72 @@ Same with mutex-meet. total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 34 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 36 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "1" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 20 - column: 5 - function: producer - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 38 - column: 3 - function: main - - entry_type: ghost_update - variable: m_locked - expression: "0" - location: - file_name: 74-mutex.c - file_hash: $FILE_HASH - line: 23 - column: 5 - function: producer - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 20 + column: 5 + function: producer + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 23 + column: 5 + function: producer + updates: + - variable: m_locked + value: "0" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 34 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 36 + column: 3 + function: main + updates: + - variable: m_locked + value: "1" + format: c_expression + - location: + file_name: 74-mutex.c + file_hash: $FILE_HASH + line: 38 + column: 3 + function: main + updates: + - variable: m_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m_locked || used == 0)' diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index b157dfed4b..4783f65092 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -1,11 +1,11 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 92-idx_priv.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 92-idx_priv.c [Success][Assert] Assertion "data == 0" will succeed (92-idx_priv.c:22:3-22:29) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 14 dead: 0 total lines: 14 [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -13,20 +13,54 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + updates: [] + - location: + file_name: 92-idx_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/29-svcomp/16-atomic_priv.t b/tests/regression/29-svcomp/16-atomic_priv.t index eea47295d5..92afedcd27 100644 --- a/tests/regression/29-svcomp/16-atomic_priv.t +++ b/tests/regression/29-svcomp/16-atomic_priv.t @@ -1,4 +1,4 @@ - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection-atomic --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -13,7 +13,7 @@ write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -21,20 +21,26 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' @@ -43,7 +49,7 @@ Non-atomic privatization: - $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 16-atomic_priv.c + $ goblint --enable ana.sv-comp.functions --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 16-atomic_priv.c [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:12:3-12:33) [Success][Assert] Assertion "myglobal == 6" will succeed (16-atomic_priv.c:14:3-14:33) [Success][Assert] Assertion "myglobal == 5" will succeed (16-atomic_priv.c:16:3-16:33) @@ -58,7 +64,7 @@ Non-atomic privatization: write with [lock:{[__VERIFIER_atomic]}, thread:[main, t_fun@16-atomic_priv.c:23:3-23:40]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:15:3-15:13) read with [mhp:{created={[main, t_fun@16-atomic_priv.c:23:3-23:40]}}, thread:[main]] (conf. 110) (exp: & myglobal) (16-atomic_priv.c:24:3-24:33) [Info][Witness] witness generation summary: - total generation entries: 4 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -66,20 +72,26 @@ Non-atomic privatization: total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 16-atomic_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 16-atomic_priv.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || myglobal == 5' diff --git a/tests/regression/36-apron/12-traces-min-rpb1.t b/tests/regression/36-apron/12-traces-min-rpb1.t index 8201b2f8f9..c0ae5c118e 100644 --- a/tests/regression/36-apron/12-traces-min-rpb1.t +++ b/tests/regression/36-apron/12-traces-min-rpb1.t @@ -56,7 +56,7 @@ format: C - $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box + $ goblint --enable warn.deterministic --set ana.activated[+] apron --set ana.path_sens[+] threadflag --enable ana.sv-comp.functions --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 12-traces-min-rpb1.c --enable ana.apron.invariant.diff-box [Warning][Assert] Assertion "g == h" is unknown. (12-traces-min-rpb1.c:27:3-27:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:16:3-16:26) [Success][Assert] Assertion "g == h" will succeed (12-traces-min-rpb1.c:29:3-29:26) @@ -76,82 +76,95 @@ dead: 0 total lines: 18 [Info][Witness] witness generation summary: - total generation entries: 10 + total generation entries: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 18 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "1" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 30 - column: 3 - function: main - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: A_locked - expression: "0" - location: - file_name: 12-traces-min-rpb1.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: A_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: A_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "0" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 18 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: A_locked + value: "0" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: A_locked + value: "1" + format: c_expression + - location: + file_name: 12-traces-min-rpb1.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + updates: + - variable: A_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (A_locked || ((0LL - (long long )g) + (long long )h diff --git a/tests/regression/56-witness/64-ghost-multiple-protecting.t b/tests/regression/56-witness/64-ghost-multiple-protecting.t index e78d0d75aa..73863eecac 100644 --- a/tests/regression/56-witness/64-ghost-multiple-protecting.t +++ b/tests/regression/56-witness/64-ghost-multiple-protecting.t @@ -1,10 +1,10 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 17 + total generation entries: 4 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -14,120 +14,138 @@ protection doesn't have precise protected invariant for g2. $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || (m1_locked || g1 == 0))' @@ -144,13 +162,13 @@ protection doesn't have precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization protection-read --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -160,120 +178,138 @@ protection doesn't have precise protected invariant for g2. protection-read has precise protected invariant for g2. $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || (m1_locked || g2 == 0))' @@ -295,13 +331,13 @@ protection-read has precise protected invariant for g2. type: assertion format: C - $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 64-ghost-multiple-protecting.c + $ goblint --set ana.base.privatization mutex-meet --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 64-ghost-multiple-protecting.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 19 dead: 0 total lines: 19 [Info][Witness] witness generation summary: - total generation entries: 18 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -309,120 +345,138 @@ protection-read has precise protected invariant for g2. total memory locations: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 19 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 64-ghost-multiple-protecting.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 19 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 64-ghost-multiple-protecting.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || ((0 <= g2 && g2 <= 1) && g1 == 0))' diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index a6e0c12b74..8115bb2921 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -1,10 +1,10 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 65-ghost-ambiguous-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 65-ghost-ambiguous-lock.c [Info][Deadcode] Logical lines of code (LLoC) summary: live: 23 dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 4 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -12,20 +12,82 @@ total memory locations: 2 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 29 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 24 + column: 3 + function: fun + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 29 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + updates: [] + - location: + file_name: 65-ghost-ambiguous-lock.c + file_hash: $FILE_HASH + line: 37 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' diff --git a/tests/regression/56-witness/66-ghost-alloc-lock.t b/tests/regression/56-witness/66-ghost-alloc-lock.t index 8e45272538..844c1e6c15 100644 --- a/tests/regression/56-witness/66-ghost-alloc-lock.t +++ b/tests/regression/56-witness/66-ghost-alloc-lock.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 66-ghost-alloc-lock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set ana.malloc.unique_address_count 1 --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 66-ghost-alloc-lock.c [Success][Assert] Assertion "g1 == 0" will succeed (66-ghost-alloc-lock.c:31:3-31:27) [Success][Assert] Assertion "g2 == 0" will succeed (66-ghost-alloc-lock.c:34:3-34:27) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -6,7 +6,7 @@ dead: 0 total lines: 23 [Info][Witness] witness generation summary: - total generation entries: 16 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 4 vulnerable: 0 @@ -14,102 +14,118 @@ total memory locations: 4 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 33 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m861095507_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 30 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "1" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 32 - column: 3 - function: main - - entry_type: ghost_update - variable: alloc_m559918035_locked - expression: "0" - location: - file_name: 66-ghost-alloc-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: alloc_m861095507_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: alloc_m559918035_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: alloc_m559918035_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: alloc_m861095507_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 10 + column: 3 + function: t_fun + updates: + - variable: alloc_m559918035_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: alloc_m559918035_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 14 + column: 3 + function: t_fun + updates: + - variable: alloc_m861095507_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 17 + column: 3 + function: t_fun + updates: + - variable: alloc_m861095507_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 30 + column: 3 + function: main + updates: + - variable: alloc_m559918035_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 32 + column: 3 + function: main + updates: + - variable: alloc_m559918035_locked + value: "0" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 33 + column: 3 + function: main + updates: + - variable: alloc_m861095507_locked + value: "1" + format: c_expression + - location: + file_name: 66-ghost-alloc-lock.c + file_hash: $FILE_HASH + line: 35 + column: 3 + function: main + updates: + - variable: alloc_m861095507_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (alloc_m861095507_locked || g2 == 0)' diff --git a/tests/regression/56-witness/67-ghost-no-unlock.t b/tests/regression/56-witness/67-ghost-no-unlock.t index 85b7a0b897..264d592366 100644 --- a/tests/regression/56-witness/67-ghost-no-unlock.t +++ b/tests/regression/56-witness/67-ghost-no-unlock.t @@ -1,11 +1,11 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 67-ghost-no-unlock.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 67-ghost-no-unlock.c [Success][Assert] Assertion "g1 == 0" will succeed (67-ghost-no-unlock.c:24:3-24:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 11 dead: 0 total lines: 11 [Info][Witness] witness generation summary: - total generation entries: 8 + total generation entries: 3 [Info][Race] Memory locations race summary: safe: 1 vulnerable: 0 @@ -13,52 +13,62 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 9 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 67-ghost-no-unlock.c - file_hash: $FILE_HASH - line: 12 - column: 3 - function: t_fun - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 9 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 12 + column: 3 + function: t_fun + updates: + - variable: m1_locked + value: "0" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 21 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 67-ghost-no-unlock.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: m1_locked + value: "1" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m1_locked || g1 == 0)' diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index 02cecfd8f6..a8f2a0226a 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 68-ghost-ambiguous-idx.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 68-ghost-ambiguous-idx.c [Warning][Assert] Assertion "data == 0" is unknown. (68-ghost-ambiguous-idx.c:24:3-24:29) [Warning][Unknown] unlocking mutex (m[4]) which may not be held (68-ghost-ambiguous-idx.c:25:3-25:30) [Info][Deadcode] Logical lines of code (LLoC) summary: @@ -10,7 +10,7 @@ write with [lock:{m[4]}, thread:[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:10:3-10:9) read with [mhp:{created={[main, t_fun@68-ghost-ambiguous-idx.c:20:3-20:40]}}, thread:[main]] (conf. 110) (exp: & data) (68-ghost-ambiguous-idx.c:24:3-24:29) [Info][Witness] witness generation summary: - total generation entries: 3 + total generation entries: 2 [Info][Race] Memory locations race summary: safe: 0 vulnerable: 0 @@ -18,20 +18,54 @@ total memory locations: 1 $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 20 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 8 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 11 + column: 3 + function: t_fun + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 20 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: [] + - location: + file_name: 68-ghost-ambiguous-idx.c + file_hash: $FILE_HASH + line: 25 + column: 3 + function: main + updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/56-witness/69-ghost-ptr-protection.t b/tests/regression/56-witness/69-ghost-ptr-protection.t index 698f643385..0b28f22b0f 100644 --- a/tests/regression/56-witness/69-ghost-ptr-protection.t +++ b/tests/regression/56-witness/69-ghost-ptr-protection.t @@ -1,4 +1,4 @@ - $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_variable", "ghost_update"]' 69-ghost-ptr-protection.c + $ goblint --set ana.base.privatization protection --enable witness.yaml.enabled --set ana.activated[+] mutexGhosts --set witness.yaml.entry-types '["flow_insensitive_invariant", "ghost_instrumentation"]' 69-ghost-ptr-protection.c [Success][Assert] Assertion "*p != 0" will succeed (69-ghost-ptr-protection.c:26:3-26:27) [Info][Deadcode] Logical lines of code (LLoC) summary: live: 15 @@ -9,7 +9,7 @@ write with [lock:{m2}, thread:[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:15:3-15:9) read with [mhp:{created={[main, t_fun@69-ghost-ptr-protection.c:22:3-22:40]}}, lock:{m1}, thread:[main]] (conf. 110) (exp: & p) (69-ghost-ptr-protection.c:26:3-26:27) [Info][Witness] witness generation summary: - total generation entries: 12 + total generation entries: 5 [Info][Race] Memory locations race summary: safe: 2 vulnerable: 0 @@ -19,66 +19,78 @@ Should not contain unsound flow-insensitive invariant m2_locked || (p == & g && *p == 0): $ yamlWitnessStrip < witness.yml - - entry_type: ghost_update - variable: multithreaded - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: main - - entry_type: ghost_update - variable: m2_locked - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m2_locked - expression: "0" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 16 - column: 3 - function: t_fun - - entry_type: ghost_update - variable: m1_locked - expression: "1" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - - entry_type: ghost_update - variable: m1_locked - expression: "0" - location: - file_name: 69-ghost-ptr-protection.c - file_hash: $FILE_HASH - line: 28 - column: 3 - function: main - - entry_type: ghost_variable - variable: multithreaded - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m2_locked - scope: global - type: int - initial: "0" - - entry_type: ghost_variable - variable: m1_locked - scope: global - type: int - initial: "0" + - entry_type: ghost_instrumentation + content: + ghost_variables: + - name: m1_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: m2_locked + scope: global + type: int + initial: + value: "0" + format: c_expression + - name: multithreaded + scope: global + type: int + initial: + value: "0" + format: c_expression + ghost_updates: + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 13 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 16 + column: 3 + function: t_fun + updates: + - variable: m2_locked + value: "0" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 22 + column: 3 + function: main + updates: + - variable: multithreaded + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 23 + column: 3 + function: main + updates: + - variable: m1_locked + value: "1" + format: c_expression + - location: + file_name: 69-ghost-ptr-protection.c + file_hash: $FILE_HASH + line: 28 + column: 3 + function: main + updates: + - variable: m1_locked + value: "0" + format: c_expression - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (m2_locked || ((0 <= *p && *p <= 1) && p == & g))' From 554bd7f72e8cac3cc226976ad6f26bc434fd38d5 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 17:01:40 +0200 Subject: [PATCH 101/103] Avoid empty ghost_instrumentation location updates --- src/analyses/mutexGhosts.ml | 7 ++- tests/regression/13-privatized/92-idx_priv.t | 28 ---------- .../56-witness/65-ghost-ambiguous-lock.t | 56 ------------------- .../56-witness/68-ghost-ambiguous-idx.t | 28 ---------- 4 files changed, 5 insertions(+), 114 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6542ab3607..6ed0da4d4c 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -218,8 +218,11 @@ struct else (variables', updates) in - let location_update = WitnessGhost.location_update' ~node ~updates in - (variables', location_update :: location_updates) + match updates with + | [] -> (variables', location_updates) (* don't add location_update with no updates *) + | _ -> + let location_update = WitnessGhost.location_update' ~node ~updates in + (variables', location_update :: location_updates) ) nodes (VariableSet.empty, []) in let entry = WitnessGhost.instrumentation_entry ~task ~variables:(VariableSet.elements variables) ~location_updates in diff --git a/tests/regression/13-privatized/92-idx_priv.t b/tests/regression/13-privatized/92-idx_priv.t index 4783f65092..261108cf2f 100644 --- a/tests/regression/13-privatized/92-idx_priv.t +++ b/tests/regression/13-privatized/92-idx_priv.t @@ -23,20 +23,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - updates: [] - location: file_name: 92-idx_priv.c file_hash: $FILE_HASH @@ -47,20 +33,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 21 - column: 3 - function: main - updates: [] - - location: - file_name: 92-idx_priv.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' diff --git a/tests/regression/56-witness/65-ghost-ambiguous-lock.t b/tests/regression/56-witness/65-ghost-ambiguous-lock.t index 8115bb2921..2771ec5c50 100644 --- a/tests/regression/56-witness/65-ghost-ambiguous-lock.t +++ b/tests/regression/56-witness/65-ghost-ambiguous-lock.t @@ -22,48 +22,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 10 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 13 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 14 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 17 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 22 - column: 3 - function: fun - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 24 - column: 3 - function: fun - updates: [] - location: file_name: 65-ghost-ambiguous-lock.c file_hash: $FILE_HASH @@ -74,20 +32,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 35 - column: 3 - function: main - updates: [] - - location: - file_name: 65-ghost-ambiguous-lock.c - file_hash: $FILE_HASH - line: 37 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= g2 && g2 <= 1)' diff --git a/tests/regression/56-witness/68-ghost-ambiguous-idx.t b/tests/regression/56-witness/68-ghost-ambiguous-idx.t index a8f2a0226a..e45399e005 100644 --- a/tests/regression/56-witness/68-ghost-ambiguous-idx.t +++ b/tests/regression/56-witness/68-ghost-ambiguous-idx.t @@ -28,20 +28,6 @@ value: "0" format: c_expression ghost_updates: - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 8 - column: 3 - function: t_fun - updates: [] - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 11 - column: 3 - function: t_fun - updates: [] - location: file_name: 68-ghost-ambiguous-idx.c file_hash: $FILE_HASH @@ -52,20 +38,6 @@ - variable: multithreaded value: "1" format: c_expression - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 23 - column: 3 - function: main - updates: [] - - location: - file_name: 68-ghost-ambiguous-idx.c - file_hash: $FILE_HASH - line: 25 - column: 3 - function: main - updates: [] - entry_type: flow_insensitive_invariant flow_insensitive_invariant: string: '! multithreaded || (0 <= data && data <= 1)' From 2c25848a23e3b74859cd4b8a7be549d572a748bc Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Thu, 21 Nov 2024 17:04:25 +0200 Subject: [PATCH 102/103] Remove support for old ghost_variable and ghost_update entry types --- src/analyses/mutexGhosts.ml | 48 -------------------- src/config/options.schema.json | 2 - src/witness/witnessGhost.ml | 16 +------ src/witness/yamlWitness.ml | 24 ++-------- src/witness/yamlWitnessType.ml | 67 ---------------------------- tests/util/yamlWitnessStripCommon.ml | 4 -- 6 files changed, 4 insertions(+), 157 deletions(-) diff --git a/src/analyses/mutexGhosts.ml b/src/analyses/mutexGhosts.ml index 6ed0da4d4c..3deec3ef59 100644 --- a/src/analyses/mutexGhosts.ml +++ b/src/analyses/mutexGhosts.ml @@ -122,54 +122,6 @@ struct | YamlEntryGlobal (g, task) -> let g: V.t = Obj.obj g in begin match g with - | `Left g' when YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type -> - let (locked, unlocked, multithread) = G.node (ctx.global g) in - let g = g' in - let entries = - (* TODO: do variable_entry-s only once *) - Locked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.variable_entry ~task (Locked l) in - Queries.YS.add entry acc - | _ -> - acc - ) (Locked.union locked unlocked) (Queries.YS.empty ()) - in - let entries = - Locked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.one in - Queries.YS.add entry acc - | _ -> - acc - ) locked entries - in - let entries = - Unlocked.fold (fun l acc -> - match mustlock_of_addr l with - | Some l when ghost_var_available ctx (Locked l) -> - let entry = WitnessGhost.update_entry ~task ~node:g (Locked l) GoblintCil.zero in - Queries.YS.add entry acc - | _ -> - acc - ) unlocked entries - in - let entries = - if not (GobConfig.get_bool "exp.earlyglobs") && multithread then ( - if ghost_var_available ctx Multithreaded then ( - let entry = WitnessGhost.variable_entry ~task Multithreaded in - let entry' = WitnessGhost.update_entry ~task ~node:g Multithreaded GoblintCil.one in - Queries.YS.add entry (Queries.YS.add entry' entries) - ) - else - entries - ) - else - entries - in - entries | `Right true when YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type -> let nodes = G.update (ctx.global g) in let (variables, location_updates) = NodeSet.fold (fun node (variables, location_updates) -> diff --git a/src/config/options.schema.json b/src/config/options.schema.json index 8534620d02..362e028ee3 100644 --- a/src/config/options.schema.json +++ b/src/config/options.schema.json @@ -2673,8 +2673,6 @@ "precondition_loop_invariant_certificate", "invariant_set", "violation_sequence", - "ghost_variable", - "ghost_update", "ghost_instrumentation" ] }, diff --git a/src/witness/witnessGhost.ml b/src/witness/witnessGhost.ml index 3535e8a347..3eaa8ef69b 100644 --- a/src/witness/witnessGhost.ml +++ b/src/witness/witnessGhost.ml @@ -1,7 +1,7 @@ (** Ghost variables for YAML witnesses. *) let enabled () = - (YamlWitness.entry_type_enabled YamlWitnessType.GhostVariable.entry_type && YamlWitness.entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type + YamlWitness.entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type module Var = WitnessGhostVar @@ -11,20 +11,6 @@ module Map = RichVarinfo.BiVarinfoMap.Make (Var) include Map -let variable_entry ~task x = - let variable = name_varinfo x in - let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) - let initial = CilType.Exp.show (initial x) in - YamlWitness.Entry.ghost_variable ~task ~variable ~type_ ~initial - -let update_entry ~task ~node x e = - let loc = Node.location node in - let location_function = (Node.find_fundec node).svar.vname in - let location = YamlWitness.Entry.location ~location:loc ~location_function in - let variable = name_varinfo x in - let expression = CilType.Exp.show e in - YamlWitness.Entry.ghost_update ~task ~location ~variable ~expression - let variable' x = let variable = name_varinfo x in let type_ = String.trim (CilType.Typ.show (typ x)) in (* CIL printer puts space at the end of some types *) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index 81072ff82d..ec9a542919 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -149,25 +149,6 @@ struct metadata = metadata (); } - let ghost_variable ~task ~variable ~type_ ~(initial): Entry.t = { - entry_type = GhostVariable { - variable; - scope = "global"; - type_; - initial; - }; - metadata = metadata ~task (); - } - - let ghost_update ~task ~location ~variable ~(expression): Entry.t = { - entry_type = GhostUpdate { - variable; - expression; - location; - }; - metadata = metadata ~task (); - } - let ghost_variable' ~variable ~type_ ~(initial): GhostInstrumentation.Variable.t = { name = variable; scope = "global"; @@ -410,9 +391,10 @@ struct entries in - (* Generate flow-insensitive entries (ghost variables and ghost updates) *) + (* Generate flow-insensitive entries (ghost instrumentation) *) let entries = - if (entry_type_enabled YamlWitnessType.GhostVariable.entry_type && entry_type_enabled YamlWitnessType.GhostUpdate.entry_type) || entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( + if entry_type_enabled YamlWitnessType.GhostInstrumentation.entry_type then ( + (* TODO: only at most one ghost_instrumentation entry can ever be produced, so this fold and deduplication is overkill *) let module EntrySet = Queries.YS in fst @@ GHT.fold (fun g v accs -> match g with diff --git a/src/witness/yamlWitnessType.ml b/src/witness/yamlWitnessType.ml index 9b5d580849..bcd8e9435f 100644 --- a/src/witness/yamlWitnessType.ml +++ b/src/witness/yamlWitnessType.ml @@ -644,61 +644,6 @@ struct {content} end -module GhostVariable = -struct - type t = { - variable: string; - scope: string; - type_: string; - initial: string; - } - [@@deriving eq, ord, hash] - - let entry_type = "ghost_variable" - - let to_yaml' {variable; scope; type_; initial} = - [ - ("variable", `String variable); - ("scope", `String scope); - ("type", `String type_); - ("initial", `String initial); - ] - - let of_yaml y = - let open GobYaml in - let+ variable = y |> find "variable" >>= to_string - and+ scope = y |> find "scope" >>= to_string - and+ type_ = y |> find "type" >>= to_string - and+ initial = y |> find "initial" >>= to_string in - {variable; scope; type_; initial} -end - -module GhostUpdate = -struct - type t = { - variable: string; - expression: string; - location: Location.t; - } - [@@deriving eq, ord, hash] - - let entry_type = "ghost_update" - - let to_yaml' {variable; expression; location} = - [ - ("variable", `String variable); - ("expression", `String expression); - ("location", Location.to_yaml location); - ] - - let of_yaml y = - let open GobYaml in - let+ variable = y |> find "variable" >>= to_string - and+ expression = y |> find "expression" >>= to_string - and+ location = y |> find "location" >>= Location.of_yaml in - {variable; expression; location} -end - module GhostInstrumentation = struct @@ -831,8 +776,6 @@ struct | PreconditionLoopInvariantCertificate of PreconditionLoopInvariantCertificate.t | InvariantSet of InvariantSet.t | ViolationSequence of ViolationSequence.t - | GhostVariable of GhostVariable.t - | GhostUpdate of GhostUpdate.t | GhostInstrumentation of GhostInstrumentation.t [@@deriving eq, ord, hash] @@ -845,8 +788,6 @@ struct | PreconditionLoopInvariantCertificate _ -> PreconditionLoopInvariantCertificate.entry_type | InvariantSet _ -> InvariantSet.entry_type | ViolationSequence _ -> ViolationSequence.entry_type - | GhostVariable _ -> GhostVariable.entry_type - | GhostUpdate _ -> GhostUpdate.entry_type | GhostInstrumentation _ -> GhostInstrumentation.entry_type let to_yaml' = function @@ -858,8 +799,6 @@ struct | PreconditionLoopInvariantCertificate x -> PreconditionLoopInvariantCertificate.to_yaml' x | InvariantSet x -> InvariantSet.to_yaml' x | ViolationSequence x -> ViolationSequence.to_yaml' x - | GhostVariable x -> GhostVariable.to_yaml' x - | GhostUpdate x -> GhostUpdate.to_yaml' x | GhostInstrumentation x -> GhostInstrumentation.to_yaml' x let of_yaml y = @@ -889,12 +828,6 @@ struct else if entry_type = ViolationSequence.entry_type then let+ x = y |> ViolationSequence.of_yaml in ViolationSequence x - else if entry_type = GhostVariable.entry_type then - let+ x = y |> GhostVariable.of_yaml in - GhostVariable x - else if entry_type = GhostUpdate.entry_type then - let+ x = y |> GhostUpdate.of_yaml in - GhostUpdate x else if entry_type = GhostInstrumentation.entry_type then let+ x = y |> GhostInstrumentation.of_yaml in GhostInstrumentation x diff --git a/tests/util/yamlWitnessStripCommon.ml b/tests/util/yamlWitnessStripCommon.ml index d54dd446bf..39bc231d72 100644 --- a/tests/util/yamlWitnessStripCommon.ml +++ b/tests/util/yamlWitnessStripCommon.ml @@ -74,10 +74,6 @@ struct InvariantSet {content = List.sort InvariantSet.Invariant.compare (List.map invariant_strip_file_hash x.content)} (* Sort, so order is deterministic regardless of Goblint. *) | ViolationSequence x -> ViolationSequence {content = List.map segment_strip_file_hash x.content} - | GhostVariable x -> - GhostVariable x (* no location to strip *) - | GhostUpdate x -> - GhostUpdate {x with location = location_strip_file_hash x.location} | GhostInstrumentation x -> GhostInstrumentation { (* Sort, so order is deterministic regardless of Goblint. *) ghost_variables = List.sort GhostInstrumentation.Variable.compare x.ghost_variables; From ffe255b9a60a1c4919b565f6c9a0e07c47ac7218 Mon Sep 17 00:00:00 2001 From: Simmo Saan Date: Fri, 29 Nov 2024 14:11:46 +0200 Subject: [PATCH 103/103] Count witness.invariant.flow_insensitive-as location invariants in summary --- src/witness/yamlWitness.ml | 2 ++ tests/regression/13-privatized/04-priv_multi.t | 2 +- tests/regression/13-privatized/74-mutex.t | 4 ++-- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/witness/yamlWitness.ml b/src/witness/yamlWitness.ml index e3978f9929..9d04b597fa 100644 --- a/src/witness/yamlWitness.ml +++ b/src/witness/yamlWitness.ml @@ -385,6 +385,7 @@ struct fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> let invariant = Entry.invariant (CilType.Exp.show inv) in let entry = Entry.location_invariant ~task ~location ~invariant in + incr cnt_location_invariant; entry :: acc ) acc | `Lifted _, _ @@ -605,6 +606,7 @@ struct fold_flow_insensitive_as_location ~inv (fun ~location ~inv acc -> let invariant = CilType.Exp.show inv in let invariant = Entry.location_invariant' ~location ~invariant in + incr cnt_location_invariant; invariant :: acc ) acc | `Bot | `Top -> (* global bot might only be possible for alloc variables, if at all, so emit nothing *) diff --git a/tests/regression/13-privatized/04-priv_multi.t b/tests/regression/13-privatized/04-priv_multi.t index af7c9b2098..1f6dff3fdc 100644 --- a/tests/regression/13-privatized/04-priv_multi.t +++ b/tests/regression/13-privatized/04-priv_multi.t @@ -215,7 +215,7 @@ Flow-insensitive invariants as location invariants. [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (04-priv_multi.c:45:10-45:11) [Warning][Deadcode][CWE-571] condition 'B > 0' is always true (04-priv_multi.c:47:9-47:14) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 9 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 10 diff --git a/tests/regression/13-privatized/74-mutex.t b/tests/regression/13-privatized/74-mutex.t index 1d750a211c..4b370db387 100644 --- a/tests/regression/13-privatized/74-mutex.t +++ b/tests/regression/13-privatized/74-mutex.t @@ -108,7 +108,7 @@ Flow-insensitive invariants as location invariants. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 2 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 3 @@ -177,7 +177,7 @@ Same with ghost_instrumentation and invariant_set entries. total lines: 15 [Warning][Deadcode][CWE-571] condition '1' (possibly inserted by CIL) is always true (74-mutex.c:19:10-19:11) [Info][Witness] witness generation summary: - location invariants: 0 + location invariants: 2 loop invariants: 0 flow-insensitive invariants: 0 total generation entries: 2