-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy paththreadId.ml
More file actions
191 lines (161 loc) · 6.5 KB
/
threadId.ml
File metadata and controls
191 lines (161 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
(** Current thread ID analysis ([threadid]). *)
module LF = LibraryFunctions
open Batteries
open Analyses
open GobList.Syntax
module Thread = ThreadIdDomain.Thread
module ThreadLifted = ThreadIdDomain.ThreadLifted
let get_current (ask: Queries.ask): ThreadLifted.t =
ask.f Queries.CurrentThreadId
let get_current_unlift ask: Thread.t =
match get_current ask with
| `Lifted thread -> thread
| _ -> failwith "ThreadId.get_current_unlift"
module VNI =
Printable.Prod3
(CilType.Varinfo)
(Node) (
Printable.Option
(WrapperFunctionAnalysis0.ThreadCreateUniqueCount)
(struct let name = "no index" end))
module Spec =
struct
include Analyses.IdentitySpec
module N =
struct
include Lattice.FlatConf (struct include Printable.DefaultConf let bot_name = "unknown node" let top_name = "unknown node" end) (VNI)
let name () = "wrapper call"
end
module TD = Thread.D
module Created =
struct
module Current =
struct
include TD
let name () = "current function"
end
module Callees =
struct
include TD
let name () = "callees"
end
include Lattice.Prod (Current) (Callees)
let name () = "created"
end
(** Uniqueness Counter * TID * (All thread creates of current thread * All thread creates of the current function and its callees) *)
module D = Lattice.Prod3 (N) (ThreadLifted) (Created)
include Analyses.ValueContexts(D)
module P = IdentityP (D)
let tids = ref (Hashtbl.create 20)
let name () = "threadid"
let context man fd ((n,current,td) as d) =
if GobConfig.get_bool "ana.thread.context.create-edges" then
d
else
(n, current, (TD.bot (), TD.bot ()))
let startstate v = (N.bot (), ThreadLifted.bot (), (TD.bot (),TD.bot ()))
let exitstate v = (N.bot (), `Lifted (Thread.threadinit v ~multiple:false), (TD.bot (), TD.bot ()))
let morphstate v _ =
let tid = Thread.threadinit v ~multiple:false in
if GobConfig.get_bool "dbg.print_tids" then
Hashtbl.replace !tids tid ();
(N.bot (), `Lifted (tid), (TD.bot (), TD.bot ()))
let create_tid ?(multiple=false) (_, current, (td, _)) ((node, index): Node.t * int option) v =
match current with
| `Lifted current ->
let+ tid = Thread.threadenter ~multiple (current, td) node index v in
if GobConfig.get_bool "dbg.print_tids" then
Hashtbl.replace !tids tid ();
`Lifted tid
| _ ->
[`Lifted (Thread.threadinit v ~multiple:true)]
let is_unique man =
man.ask Queries.MustBeUniqueThread
let enter man lval f args =
let (n, current, (td, _)) = man.local in
[man.local, (n, current, (td,TD.bot ()))]
let combine_env man lval fexp f args fc ((n,current,(_, au_ftd)) as au) f_ask =
let (_, _, (td, ftd)) = man.local in
if not (GobConfig.get_bool "ana.thread.context.create-edges") then
(n,current,(TD.join td au_ftd, TD.join ftd au_ftd))
else
au
let created (_, current, (td, _)) =
match current with
| `Lifted current -> BatOption.map_default (ConcDomain.ThreadSet.of_list) (ConcDomain.ThreadSet.top ()) (Thread.created current td)
| _ -> ConcDomain.ThreadSet.top ()
let query (man: (D.t, _, _, _) man) (type a) (x: a Queries.t): a Queries.result =
match x with
| Queries.CurrentThreadId -> Tuple3.second man.local
| Queries.CreatedThreads -> created man.local
| Queries.MustBeUniqueThread ->
begin match Tuple3.second man.local with
| `Lifted tid -> Thread.is_unique tid
| _ -> Queries.MustBool.top ()
end
| Queries.MustBeSingleThreaded {since_start} ->
begin match Tuple3.second man.local with
| `Lifted tid when Thread.is_main tid ->
let created = created man.local in
if since_start then
ConcDomain.ThreadSet.is_empty created
else if man.ask Queries.ThreadsJoinedCleanly then
let joined = man.ask Queries.MustJoinedThreads in
ConcDomain.ThreadSet.is_empty (ConcDomain.ThreadSet.diff created joined)
else
false
| _ -> false
end
| _ -> Queries.Result.top x
module A =
struct
include Printable.Option (ThreadLifted) (struct let name = "nonunique" end)
let name () = "thread"
let may_race (t1: t) (t2: t) =
let use_tid = GobConfig.get_bool "ana.race.digests.thread" in
(not use_tid) ||
match t1, t2 with
| Some t1, Some t2 when ThreadLifted.equal t1 t2 -> false (* only unique threads *)
| _, _ -> true
let should_print = Option.is_some
end
let access man _ =
if is_unique man then
let tid = Tuple3.second man.local in
Some tid
else
None
(** get the node that identifies the current context, possibly that of a wrapper function *)
let indexed_node_for_man man =
match man.ask Queries.ThreadCreateIndexedNode with
| `Lifted node, count when WrapperFunctionAnalysis.ThreadCreateUniqueCount.is_top count -> node, None
| `Lifted node, count -> node, Some count
| (`Bot | `Top), _ -> man.prev_node, None
let threadenter man ~multiple lval f args:D.t list =
let n, i = indexed_node_for_man man in
let+ tid = create_tid ~multiple man.local (n, i) f in
(`Lifted (f, n, i), tid, (TD.bot (), TD.bot ()))
let threadspawn man ~multiple lval f args fman =
let (current_n, current, (td,tdl)) = man.local in
let v, n, i = match fman.local with `Lifted vni, _, _ -> vni | _ -> failwith "ThreadId.threadspawn" in
(current_n, current, (Thread.threadspawn ~multiple td n i v, Thread.threadspawn ~multiple tdl n i v))
type marshal = (Thread.t,unit) Hashtbl.t (* TODO: don't use polymorphic Hashtbl *)
let init (m:marshal option): unit =
match m with
| Some y -> tids := y
| None -> ()
let print_tid_info () =
let tids = Hashtbl.to_list !tids in
let uniques = List.filter_map (fun (a,b) -> if Thread.is_unique a then Some a else None) tids in
let non_uniques = List.filter_map (fun (a,b) -> if not (Thread.is_unique a) then Some a else None) tids in
let uc = List.length uniques in
let nc = List.length non_uniques in
M.debug_noloc ~category:Analyzer "Encountered number of thread IDs (unique): %i (%i)" (uc+nc) uc;
M.msg_group Debug ~category:Analyzer "Unique TIDs" (List.map (fun tid -> (Thread.pretty () tid, None)) uniques);
M.msg_group Debug ~category:Analyzer "Non-unique TIDs" (List.map (fun tid -> (Thread.pretty () tid, None)) non_uniques)
let finalize () =
if GobConfig.get_bool "dbg.print_tids" then print_tid_info ();
!tids
end
let _ =
MCP.register_analysis (module Spec : MCPSpec)