@@ -46,6 +46,9 @@ module type S =
4646 val thread_return : Q .ask -> (V .t -> G .t ) -> (V .t -> G .t -> unit ) -> ThreadIdDomain.Thread .t -> relation_components_t -> relation_components_t
4747 val iter_sys_vars : (V .t -> G .t ) -> VarQuery .t -> V .t VarQuery .f -> unit (* * [Queries.IterSysVars] for apron. *)
4848
49+ val invariant_global : Q .ask -> (V .t -> G .t ) -> V .t -> Invariant .t
50+ (* * Returns flow-insensitive invariant for global unknown. *)
51+
4952 val invariant_vars : Q .ask -> (V .t -> G .t ) -> relation_components_t -> varinfo list
5053 (* * Returns global variables which are privatized. *)
5154
@@ -137,6 +140,7 @@ struct
137140 {rel = RD. top () ; priv = startstate () }
138141
139142 let iter_sys_vars getg vq vf = ()
143+ let invariant_global ask getg g = Invariant. none
140144 let invariant_vars ask getg st = []
141145
142146 let init () = ()
@@ -424,6 +428,7 @@ struct
424428 {rel = getg () ; priv = startstate () }
425429
426430 let iter_sys_vars getg vq vf = () (* TODO: or report singleton global for any Global query? *)
431+ let invariant_global ask getg g = Invariant. none
427432 let invariant_vars ask getg st = protected_vars ask (* TODO: is this right? *)
428433
429434 let finalize () = ()
@@ -708,6 +713,41 @@ struct
708713
709714 let init () = ()
710715 let finalize () = ()
716+
717+ let invariant_global (ask : Q.ask ) (getg : V.t -> G.t ): V.t -> Invariant.t = function
718+ | `Left m' -> (* mutex *)
719+ let atomic = LockDomain.MustLock. equal m' (LockDomain.MustLock. of_var LibraryFunctions. verifier_atomic_var) in
720+ if atomic || ask.f (GhostVarAvailable (Locked m')) then (
721+ (* filters like query_invariant *)
722+ let one_var = GobConfig. get_bool " ana.relation.invariant.one-var" in
723+ let exact = GobConfig. get_bool " witness.invariant.exact" in
724+
725+ 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. *)
726+ let inv =
727+ RD. invariant rel
728+ |> List. enum
729+ |> Enum. filter_map (fun (lincons1 : Apron.Lincons1.t ) ->
730+ (* filter one-vars and exact *)
731+ (* TODO: exact filtering doesn't really work with octagon because it returns two SUPEQ constraints instead *)
732+ if (one_var || GobApron.Lincons1. num_vars lincons1 > = 2 ) && (exact || Apron.Lincons1. get_typ lincons1 <> EQ ) then
733+ RD. cil_exp_of_lincons1 lincons1
734+ |> Option. filter (fun exp -> not (InvariantCil. exp_contains_tmp exp))
735+ else
736+ None
737+ )
738+ |> Enum. fold (fun acc x -> Invariant. (acc && of_exp x)) Invariant. none
739+ in
740+ if atomic then
741+ inv
742+ else (
743+ let var = WitnessGhost. to_varinfo (Locked m') in
744+ Invariant. (of_exp (Lval (GoblintCil. var var)) || inv) [@ coverage off] (* bisect_ppx cannot handle redefined (||) *)
745+ )
746+ )
747+ else
748+ Invariant. none
749+ | g -> (* global *)
750+ Invariant. none (* Could output unprotected one-variable (so non-relational) invariants, but probably not very useful. [BasePriv] does those anyway. *)
711751end
712752
713753(* * May written variables. *)
@@ -1275,6 +1315,8 @@ struct
12751315 | _ -> ()
12761316
12771317 let finalize () = ()
1318+
1319+ let invariant_global ask getg g = Invariant. none
12781320end
12791321
12801322module TracingPriv = functor (Priv : S ) -> functor (RD : RelationDomain.RD ) ->
0 commit comments