Skip to content
Open
Show file tree
Hide file tree
Changes from 56 commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
7831cbf
add inter-procedural lock c files
dabund24 Oct 17, 2025
3ef7082
add lock-fork hb relationship c file
dabund24 Oct 17, 2025
9d88584
use pthread_create() and pthread_join() instead of race macros for in…
dabund24 Nov 5, 2025
b7d0d35
activate creationLockset analysis for inter-threaded lock regressions…
dabund24 Nov 5, 2025
93a513a
initial version of creationLockset analysis
dabund24 Nov 5, 2025
946536b
AncestorLocksetSpec as common base module
dabund24 Nov 7, 2025
a78e44c
initial version of TaintedCreationLockset analysis
dabund24 Nov 7, 2025
8ba9094
use thread domain instead of lifted thread domain
dabund24 Nov 7, 2025
ead4843
add threadJoins as dependency for TaintedCreationLockset analysis
dabund24 Nov 7, 2025
73e6d9c
initial version of transitive descendants analysis
dabund24 Nov 7, 2025
f212c45
some comments in transitiveDescendats analysis
dabund24 Nov 7, 2025
4633ec7
query for descendant analysis
dabund24 Nov 11, 2025
3f3e2f3
get rid of unnecessary match expression
dabund24 Nov 15, 2025
691cdfd
MayCreationLockset query
dabund24 Nov 16, 2025
61d5c3f
InterThreadedLockset query
dabund24 Nov 16, 2025
e1719b2
fix incorrect query answer type in transitive descendants analysis
dabund24 Nov 16, 2025
8720b23
cartesian product helper functions
dabund24 Nov 18, 2025
7c6e5d9
remove unused function from TaintedCreationLocksetSpec
dabund24 Nov 18, 2025
61a48dc
correct comment in tainted lockset analysis
dabund24 Nov 18, 2025
31ceff8
replace threadset and lockset module references with shorthand
dabund24 Nov 18, 2025
450d349
function for getting currently running tids
dabund24 Nov 18, 2025
7d1fa1a
inter-threaded lockset A module
dabund24 Nov 19, 2025
3c52c76
use topped set for global domain in AncestorLocksetSpec
dabund24 Nov 19, 2025
8b1727f
replace comparison operators with equals function of domains
dabund24 Nov 19, 2025
b0751dc
add creationLockset analysis to dependencies of taintedCreationLockse…
dabund24 Nov 19, 2025
09f28ba
fix regression test files
dabund24 Nov 19, 2025
ea5a72a
move test files to better locations
dabund24 Nov 19, 2025
0b0fae8
remove unused inter threaded lockset query
dabund24 Nov 20, 2025
3a5513d
hash descendant thread query param
dabund24 Nov 20, 2025
cecf244
transitive version of (tainted) creation locksets
dabund24 Nov 20, 2025
55184fe
add race and transitive descendants analyses as dependencies to creat…
dabund24 Nov 20, 2025
611a91e
regression tests for transitive creation locksets
dabund24 Nov 20, 2025
c1ad680
rename regression test for second case
dabund24 Nov 20, 2025
70dabb7
add thread param to MayCreationLockset query
dabund24 Nov 20, 2025
0e63731
handle unlock of unknown mutex
dabund24 Nov 20, 2025
3514a37
edit some comments
dabund24 Nov 20, 2025
19ce960
Merge branch 'goblint:master' into master
dabund24 Nov 20, 2025
61b9609
remove redundant must-ancestor check
dabund24 Dec 4, 2025
52ce9f0
fix and update some comments
dabund24 Dec 4, 2025
7f4e531
minimize contributions to tcl when unlock of unknown thread is encoun…
dabund24 Dec 4, 2025
2158f23
align naming style of A module with other modules
dabund24 Dec 4, 2025
e531002
Merge branch 'master' into master
dabund24 Dec 4, 2025
85aad48
remove irrelevant test case
dabund24 Dec 4, 2025
4b9c2c7
add new modules to goblint_lib
dabund24 Dec 4, 2025
2b62168
add params to tests
dabund24 Dec 4, 2025
dbf73f1
remove comment/question concerning contexts
dabund24 Dec 5, 2025
e1299ea
align hash calls for threads in queries with other hash calls
dabund24 Dec 5, 2025
87dde05
move address to must lock conversion from mutex ghosts/creation locks…
dabund24 Dec 5, 2025
b8416ef
should_print in A module
dabund24 Dec 5, 2025
13443f9
impose conditions on config before running creation lockset analyses
dabund24 Dec 5, 2025
f1efd32
remove bad semicolon
dabund24 Dec 5, 2025
6ec28ca
ambiguous thread creation test cases
dabund24 Dec 8, 2025
1879e7e
more racefree test cases
dabund24 Dec 8, 2025
5b97ec4
more racing test cases
dabund24 Dec 8, 2025
fc22ec0
use "RACE!" instead of "RACE"
dabund24 Dec 8, 2025
4ac477e
Merge branch 'master' into master
dabund24 Dec 8, 2025
695081c
remove unused LibraryFunctions import
dabund24 Dec 9, 2025
5bf35ca
add query parameters to result of pretty function
dabund24 Dec 9, 2025
8d5928e
add missing `return NULL;`
dabund24 Dec 9, 2025
873ff0c
remove redundant `;;`
dabund24 Dec 9, 2025
b495fa9
undo accidental changes to `raceAnalysis.ml`
dabund24 Dec 9, 2025
3c45dff
remove redundant `;;` in `creationLockset.ml`
dabund24 Dec 9, 2025
6c2c849
remove debug statements accidentally committed
dabund24 Dec 9, 2025
1db14cb
add ambiguous context regression test
dabund24 Dec 10, 2025
099f742
change global domain for creation lockset analysis
dabund24 Dec 10, 2025
850e1cb
remove creation lockset query
dabund24 Dec 10, 2025
76c14dd
remove config constraints for creation lockset analysis
dabund24 Dec 10, 2025
1f3cdef
remove query function from creation lockset analysis
dabund24 Dec 10, 2025
72afe4a
enforce must-ancestor property in unlock transfer function
dabund24 Dec 10, 2025
3b494d9
remove some semi-colons
dabund24 Dec 10, 2025
583a41f
fix comments for test files
dabund24 Dec 10, 2025
744f584
reorder some statements in event transition function
dabund24 Dec 11, 2025
648de9a
comment on applying setminus to bottom
dabund24 Dec 11, 2025
772cf03
move domain type dafinition back from queries to analysis
dabund24 Dec 11, 2025
a8479fe
move comment explaining the analysis to top of file
dabund24 Dec 11, 2025
14d195f
fix an outdated comment
dabund24 Dec 11, 2025
a0c2446
rename descendants analysis
dabund24 Dec 11, 2025
048ca71
make threadspawn transfer function in descendants analysis a little l…
dabund24 Dec 11, 2025
a677314
top comment for thread descendants analysis
dabund24 Dec 11, 2025
97a6967
re-add an empty line, which was removed in a previous commit
dabund24 Dec 11, 2025
2c9c39d
remove redundant and inaccurate comment
dabund24 Dec 11, 2025
c36d6d1
must_ancestors function for thread ids
dabund24 Dec 12, 2025
3c1a51f
must_ancestors test
dabund24 Dec 12, 2025
32c76cd
Merge branch 'master' into master
dabund24 Dec 12, 2025
34f4e9f
change return type of must_ancestors to not be an option
dabund24 Dec 14, 2025
5403dfd
initial version of alternative analysis
dabund24 Dec 14, 2025
7770141
tests for alternative analysis
dabund24 Dec 14, 2025
169b60f
compare functions for queries
dabund24 Dec 15, 2025
fe3c133
give tests for alternative implementation non-unique names
dabund24 Dec 15, 2025
edda5d8
one more norace test case
dabund24 Dec 15, 2025
b011914
consistant * style in tests
dabund24 Dec 15, 2025
8aa1490
circle -> cycle
dabund24 Dec 15, 2025
57cf4a8
clean up creation lockset alternative file
dabund24 Dec 15, 2025
82ecd93
fix dependency analyses names
dabund24 Dec 15, 2025
135ce02
update module comments for alternative creation lockset analysis
dabund24 Dec 15, 2025
2054f59
cl -> il in A module of alternative analysis
dabund24 Dec 15, 2025
6b8c3f3
restructure unlock and unknown unlock of alternative creation lockset…
dabund24 Dec 15, 2025
db4cdf9
Merge branch 'master' into master
dabund24 Dec 15, 2025
0df9c76
update outdated comment in thread id domain
dabund24 Dec 15, 2025
00ca4df
norace -> racefree aligning test names with those of other tests
dabund24 Dec 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
210 changes: 210 additions & 0 deletions src/analyses/creationLockset.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
(** Ancestor-lock analysis. See https://github.com/goblint/analyzer/pull/1865 *)

open Analyses
module LF = LibraryFunctions
module TID = ThreadIdDomain.Thread
module TIDs = ConcDomain.ThreadSet
module LID = LockDomain.MustLock
module LIDs = LockDomain.MustLockset

(** common base for [CreationLocksetSpec] and [TaintedCreationLocksetSpec] *)
module AncestorLocksetSpec = struct
include IdentityUnitContextsSpec
module D = Lattice.Unit

module V = struct
include TID
include StdV
end

(** 2 ^ { [TID] \times [LID] } *)
module G = Queries.ALS

let startstate _ = D.bot ()
let exitstate _ = D.bot ()

(** register a contribution to a global: global.[child_tid] \supseteq [to_contribute]
@param man man at program point
@param to_contribute new edges from [child_tid] to register
@param child_tid
*)
let contribute_lock man to_contribute child_tid = man.sideg child_tid to_contribute

(** compute [tids] \times \{[lock]\} *)
let singleton_cartesian_prod tids lock =
TIDs.fold (fun tid acc -> G.add (tid, lock) acc) tids (G.empty ())
;;

(** compute the cartesian product [tids] \times [locks] *)
let cartesian_prod tids locks =
LIDs.fold
(fun lock acc ->
let tids_times_lock = singleton_cartesian_prod tids lock in
G.union tids_times_lock acc)
locks
(G.empty ())
;;

(** reflexive-transitive closure of child relation applied to [tid]
@param ask any ask
@param tid
@returns [{ tid }] \cup DES([tid])
*)
let descendants_closure (ask : Queries.ask) tid =
let transitive_descendants = ask.f @@ Queries.DescendantThreads tid in
TIDs.add tid transitive_descendants
;;
end

(** collects for each thread t_n pairs of ancestors and locks (t_0,l):
when t_n or an ancestor t_1 of t_n was created, the creating thread t_0 must have held l.
*)
module CreationLocksetSpec = struct
include AncestorLocksetSpec

let name () = "creationLockset"

(** create(t_1) in t_0 with lockset L *)
let threadspawn man ~multiple lval f args fman =
let ask = Analyses.ask_of_man man in
let tid_lifted = ask.f Queries.CurrentThreadId in
let child_ask = Analyses.ask_of_man fman in
let child_tid_lifted = child_ask.f Queries.CurrentThreadId in
match tid_lifted, child_tid_lifted with
| `Lifted tid, `Lifted child_tid ->
let descendants = descendants_closure child_ask child_tid in
let lockset = ask.f Queries.MustLockset in
let to_contribute = cartesian_prod (TIDs.singleton tid) lockset in
TIDs.iter (contribute_lock man to_contribute) descendants
| _ -> (* TODO deal with top or bottom? *) ()
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it mean for a thread id to be top or bottom? Not sure how to deal with this here and in some other places

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should usually not happen. If it does, I think the best is to assume that all bets are off.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you suggest emitting a warning or something similar here or can I keep everything the way it is? (except for removing the comments of course)

;;

let query man (type a) (x : a Queries.t) : a Queries.result =
match x with
| Queries.MayCreationLockset tid -> (man.global tid : G.t)
| _ -> Queries.Result.top x
;;
end

(** collects for each thread t_n pairs of ancestors and locks (t_0,l):
l may be unlocked in t_0 while t_n could be running.
*)
module TaintedCreationLocksetSpec = struct
include AncestorLocksetSpec

let name () = "taintedCreationLockset"

(** compute all threads that may run along with the ego thread at a program point
@param ask ask of ego thread at the program point
*)
let get_possibly_running_tids (ask : Queries.ask) =
let may_created_tids = ask.f Queries.CreatedThreads in
let may_transitively_created_tids =
TIDs.fold
(fun child_tid acc -> TIDs.union acc (descendants_closure ask child_tid))
may_created_tids
(TIDs.empty ())
in
let must_joined_tids = ask.f Queries.MustJoinedThreads in
TIDs.diff may_transitively_created_tids must_joined_tids
;;

let event man e _ =
match e with
| Events.Unlock addr ->
let ask = Analyses.ask_of_man man in
let tid_lifted = ask.f Queries.CurrentThreadId in
(match tid_lifted with
| `Top | `Bot -> ()
| `Lifted tid ->
let possibly_running_tids = get_possibly_running_tids ask in
let lock_opt = LockDomain.MustLock.of_addr addr in
(match lock_opt with
| Some lock ->
(* contribute for all possibly_running_tids: (tid, lock) *)
let to_contribute = G.singleton (tid, lock) in
TIDs.iter (contribute_lock man to_contribute) possibly_running_tids
| None ->
(* any lock could have been unlocked. Contribute for all possibly_running_tids all members of their CreationLocksets with the ego thread to invalidate them!! *)
let contribute_creation_lockset des_tid =
let full_creation_lockset = ask.f @@ Queries.MayCreationLockset des_tid in
let filtered_creation_lockset =
G.filter (fun (t, _l) -> t = tid) full_creation_lockset
in
man.sideg des_tid filtered_creation_lockset
in
TIDs.iter contribute_creation_lockset possibly_running_tids))
| _ -> ()
;;

module A = struct
(** ego tid * lockset * inter-threaded lockset *)
include Printable.Prod3 (TID) (LIDs) (G)

let name () = "interThreadedLockset"

(** checks if [itls1] has a member ([tp1], [l]) such that [itls2] has a member ([tp2], [l]) with [tp1] != [tp2]
@param itls1 inter-threaded lockset of first thread [t1]
@param itls2 inter-threaded lockset of second thread [t2]
@returns whether [t1] and [t2] must be running mutually exclusive
*)
let both_protected_inter_threaded itls1 itls2 =
let itls2_has_same_lock_other_tid (tp1, l1) =
G.exists (fun (tp2, l2) -> LID.equal l1 l2 && (not @@ TID.equal tp1 tp2)) itls2
in
G.exists itls2_has_same_lock_other_tid itls1
;;

(** checks if [itls1] has a member ([tp1], [l1]) such that [l1] is in [ls2] and [tp1] != [t2]
@param itls1 inter-threaded lockset of thread [t1] at first program point
@param t2 thread id at second program point
@param ls2 lockset at second program point
@returns whether [t1] must be running mutually exclusive with second program point
*)
let one_protected_inter_threaded_other_intra_threaded itls1 t2 ls2 =
G.exists (fun (tp1, l1) -> LIDs.mem l1 ls2 && (not @@ TID.equal tp1 t2)) itls1
;;

let may_race (t1, ls1, itls1) (t2, ls2, itls2) =
not
(both_protected_inter_threaded itls1 itls2
|| one_protected_inter_threaded_other_intra_threaded itls1 t2 ls2
|| one_protected_inter_threaded_other_intra_threaded itls2 t1 ls1)
;;

let should_print (_t, _ls, itls) = not @@ G.is_empty itls
end

let access man _ =
let ask = Analyses.ask_of_man man in
let tid_lifted = ask.f Queries.CurrentThreadId in
match tid_lifted with
| `Lifted tid ->
let lockset = ask.f Queries.MustLockset in
let creation_lockset = ask.f @@ Queries.MayCreationLockset tid in
let tainted_creation_lockset = man.global tid in
(* all values in creation lockset, but not in tainted creation lockset *)
let inter_threaded_lockset = G.diff creation_lockset tainted_creation_lockset in
tid, lockset, inter_threaded_lockset
| _ -> ThreadIdDomain.UnknownThread, LIDs.empty (), G.empty ()
;;
end

let _ =
MCP.register_analysis
~dep:[ "threadid"; "mutex"; "race"; "transitiveDescendants" ]
(module CreationLocksetSpec : MCPSpec)
;;

let _ =
MCP.register_analysis
~dep:
[ "threadid"
; "mutex"
; "threadJoins"
; "race"
; "transitiveDescendants"
; "creationLockset"
]
(module TaintedCreationLocksetSpec : MCPSpec)
;;
15 changes: 5 additions & 10 deletions src/analyses/mutexGhosts.ml
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@ struct
let create_update = create_threadcreate
end

let mustlock_of_addr (addr: LockDomain.Addr.t): LockDomain.MustLock.t option =
match addr with
| Addr mv when LockDomain.Mval.is_definite mv -> Some (LockDomain.MustLock.of_mval mv)
| _ -> None

let event man e oman =
let verifier_atomic_addr = LockDomain.Addr.of_var LibraryFunctions.verifier_atomic_var in
begin match e with
Expand All @@ -78,7 +73,7 @@ struct
Locked.iter (fun lock ->
Option.iter (fun lock ->
man.sideg (V.lock lock) (G.create_lock true)
) (mustlock_of_addr lock)
) (LockDomain.MustLock.of_addr lock)
) locked
);
)
Expand All @@ -91,7 +86,7 @@ struct
Locked.iter (fun lock ->
Option.iter (fun lock ->
man.sideg (V.lock lock) (G.create_lock true)
) (mustlock_of_addr lock)
) (LockDomain.MustLock.of_addr lock)
) unlocked
);
)
Expand Down Expand Up @@ -128,7 +123,7 @@ struct
let (locked, unlocked, multithread) = G.node (man.global (V.node node)) in
let variables' =
Locked.fold (fun l acc ->
match mustlock_of_addr l with
match LockDomain.MustLock.of_addr l with
| Some l when ghost_var_available man (Locked l) ->
let variable = WitnessGhost.variable' (Locked l) in
VariableSet.add variable acc
Expand All @@ -138,7 +133,7 @@ struct
in
let updates =
Locked.fold (fun l acc ->
match mustlock_of_addr l with
match LockDomain.MustLock.of_addr l with
| Some l when ghost_var_available man (Locked l) ->
let update = WitnessGhost.update' (Locked l) GoblintCil.one in
update :: acc
Expand All @@ -148,7 +143,7 @@ struct
in
let updates =
Unlocked.fold (fun l acc ->
match mustlock_of_addr l with
match LockDomain.MustLock.of_addr l with
| Some l when ghost_var_available man (Locked l) ->
let update = WitnessGhost.update' (Locked l) GoblintCil.zero in
update :: acc
Expand Down
45 changes: 45 additions & 0 deletions src/analyses/transitiveDescendants.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
open Analyses
module TID = ThreadIdDomain.Thread

(** flow-insensitive analysis mapping threads to may-sets of descendants *)
module TransitiveDescendants = struct
include IdentityUnitContextsSpec
module D = Lattice.Unit

module V = struct
include TID
include StdV
end

module G = ConcDomain.ThreadSet

let name () = "transitiveDescendants"
let startstate _ = D.bot ()
let exitstate _ = D.bot ()

let query man (type a) (x : a Queries.t) : a Queries.result =
match x with
| Queries.DescendantThreads t -> (man.global t : G.t)
| _ -> Queries.Result.top x
;;

let threadspawn man ~multiple lval f args fman =
let ask = Analyses.ask_of_man man in
let tid_lifted = ask.f Queries.CurrentThreadId in
match tid_lifted with
| `Top | `Bot -> ()
| `Lifted tid ->
let child_ask = Analyses.ask_of_man fman in
let child_tid_lifted = child_ask.f Queries.CurrentThreadId in
(match child_tid_lifted with
| `Top | `Bot -> ()
| `Lifted child_tid ->
(* contribute new child *)
let _ = man.sideg tid (G.singleton child_tid) in
(* transitive closure *)
let child_descendants = man.global child_tid in
man.sideg tid child_descendants)
;;
end

let _ = MCP.register_analysis ~dep:[ "threadid" ] (module TransitiveDescendants : MCPSpec)
5 changes: 5 additions & 0 deletions src/cdomains/lockDomain.ml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ struct
let of_mval ((v, o): Mval.t): t =
(v, Offset.Poly.map_indices (fun i -> IndexDomain.to_int i |> Option.get) o)

let of_addr (addr : Addr.t) : t option =
match addr with
| Addr mv when Mval.is_definite mv -> Some (of_mval mv)
| _ -> None

let to_mval ((v, o): t): Mval.t =
(v, Offset.Poly.map_indices (IndexDomain.of_int (Cilfacade.ptrdiff_ikind ())) o)
end
Expand Down
13 changes: 13 additions & 0 deletions src/domains/queries.ml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ type invariant_context = Invariant.context = {

module YS = SetDomain.ToppedSet (YamlWitnessType.Entry) (struct let topname = "Top" end)

module ALS = SetDomain.ToppedSet (Printable.Prod (ThreadIdDomain.Thread) (LockDomain.MustLock)) (struct let topname = "all pairs of threads and locks" end)

(** GADT for queries with specific result type. *)
type _ t =
Expand Down Expand Up @@ -146,6 +147,8 @@ type _ 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 (** 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. *)
| DescendantThreads: ThreadIdDomain.Thread.t -> ConcDomain.ThreadSet.t t
| MayCreationLockset: ThreadIdDomain.Thread.t -> ALS.t t

type 'a result = 'a

Expand Down Expand Up @@ -221,6 +224,8 @@ struct
| YamlEntryGlobal _ -> (module YS)
| GhostVarAvailable _ -> (module MayBool)
| InvariantGlobalNodes -> (module NS)
| DescendantThreads _ -> (module ConcDomain.ThreadSet)
| MayCreationLockset _ -> (module ALS)

(** Get bottom result for query. *)
let bot (type a) (q: a t): a result =
Expand Down Expand Up @@ -295,6 +300,8 @@ struct
| YamlEntryGlobal _ -> YS.top ()
| GhostVarAvailable _ -> MayBool.top ()
| InvariantGlobalNodes -> NS.top ()
| DescendantThreads _ -> ConcDomain.ThreadSet.top ()
| MayCreationLockset _ -> ALS.top ()
end

(* The type any_query can't be directly defined in Any as t,
Expand Down Expand Up @@ -366,6 +373,8 @@ struct
| Any (MustProtectingLocks _) -> 61
| Any (GhostVarAvailable _) -> 62
| Any InvariantGlobalNodes -> 63
| Any (DescendantThreads _) -> 64
| Any (MayCreationLockset _) -> 65

let rec compare a b =
let r = Stdlib.compare (order a) (order b) in
Expand Down Expand Up @@ -472,6 +481,8 @@ struct
| Any (MaySignedOverflow e) -> CilType.Exp.hash e
| Any (GasExhausted f) -> CilType.Fundec.hash f
| Any (GhostVarAvailable v) -> WitnessGhostVar.hash v
| Any (DescendantThreads t) -> ThreadIdDomain.Thread.hash t
| Any (MayCreationLockset t) -> ThreadIdDomain.Thread.hash t
(* 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. *)
Expand Down Expand Up @@ -540,6 +551,8 @@ struct
| Any (GasExhausted f) -> Pretty.dprintf "GasExhausted %a" CilType.Fundec.pretty f
| Any (GhostVarAvailable v) -> Pretty.dprintf "GhostVarAvailable %a" WitnessGhostVar.pretty v
| Any InvariantGlobalNodes -> Pretty.dprintf "InvariantGlobalNodes"
| Any (DescendantThreads t) -> Pretty.dprintf "DescendantThreads"
| Any (MayCreationLockset t) -> Pretty.dprintf "MayCreationLockset"
end

let to_value_domain_ask (ask: ask) =
Expand Down
Loading
Loading