-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathanalyses.ml
More file actions
446 lines (346 loc) · 13.3 KB
/
analyses.ml
File metadata and controls
446 lines (346 loc) · 13.3 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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
(** {{!Spec} Analysis specification} signatures. *)
open GoblintCil
open Pretty
open GobConfig
module M = Messages
(** Analysis starts from lists of functions: start functions, exit functions, and
* other functions. *)
type fundecs = fundec list * fundec list * fundec list
module Var =
struct
type t = Node.t [@@deriving eq, ord, hash, relift]
let printXml f n =
let l = Node.location n in
BatPrintf.fprintf f "<call id=\"%s\" file=\"%s\" fun=\"%s\" line=\"%d\" order=\"%d\" column=\"%d\">\n" (Node.show_id n) l.file (Node.find_fundec n).svar.vname l.line l.byte l.column
let var_id = Node.show_id
end
module VarF (LD: Printable.S) =
struct
type t = Node.t * LD.t [@@deriving eq, ord, hash]
let relift (n,x) = n, LD.relift x
let getLocation (n,d) = Node.location n
let pretty_trace () ((n,c) as x) =
if get_bool "dbg.trace.context" then dprintf "(%a, %a) on %a" Node.pretty_trace n LD.pretty c CilType.Location.pretty (getLocation x)
(* if get_bool "dbg.trace.context" then dprintf "(%a, %d) on %a" Node.pretty_trace n (LD.tag c) CilType.Location.pretty (getLocation x) *)
else dprintf "%a on %a" Node.pretty_trace n CilType.Location.pretty (getLocation x)
let printXml f (n,c) =
Var.printXml f n;
BatPrintf.fprintf f "<context>\n";
LD.printXml f c;
BatPrintf.fprintf f "</context>\n"
let var_id (n,_) = Var.var_id n
let node (n,_) = n
let is_write_only _ = false
end
module type SpecSysVar =
sig
include Printable.S
include Goblint_constraint.ConstrSys.SysVar with type t := t
end
module GVarF (V: SpecSysVar) =
struct
include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (V) (CilType.Fundec)
let name () = "FromSpec"
let spec x = `Left x
let contexts x = `Right x
(* from Basetype.Variables *)
let var_id = show
let node _ = MyCFG.Function Cil.dummyFunDec
let pretty_trace = pretty
let is_write_only = function
| `Left x -> V.is_write_only x
| `Right _ -> true
end
module GVarFC (V:SpecSysVar) (C:Printable.S) =
struct
include Printable.EitherConf (struct let expand1 = false let expand2 = true end) (V) (Printable.Prod (CilType.Fundec) (C))
let name () = "FromSpec"
let spec x = `Left x
let call (x, c) = `Right (x, c)
(* from Basetype.Variables *)
let var_id = show
let node _ = MyCFG.Function Cil.dummyFunDec
let pretty_trace = pretty
let is_write_only = function
| `Left x -> V.is_write_only x
| `Right _ -> true
end
module GVarG (G: Lattice.S) (C: Printable.S) =
struct
module CSet =
struct
include SetDomain.Make (
struct
include C
let printXml f c = BatPrintf.fprintf f "<value>%a</value>" printXml c (* wrap in <value> for HTML printing *)
end
)
let name () = "contexts"
end
include Lattice.Lift2 (G) (CSet)
let spec = function
| `Bot -> G.bot ()
| `Lifted1 x -> x
| _ -> failwith "GVarG.spec"
let contexts = function
| `Bot -> CSet.bot ()
| `Lifted2 x -> x
| _ -> failwith "GVarG.contexts"
let create_spec spec = `Lifted1 spec
let create_contexts contexts = `Lifted2 contexts
let printXml f = function
| `Lifted1 x -> G.printXml f x
| `Lifted2 x -> BatPrintf.fprintf f "<analysis name=\"fromspec-contexts\">%a</analysis>" CSet.printXml x
| x -> BatPrintf.fprintf f "<analysis name=\"fromspec\">%a</analysis>" printXml x
end
exception Deadcode
(** [Dom (D)] produces D lifted where bottom means dead-code *)
module Dom (LD: Lattice.S) =
struct
include Lattice.LiftConf (struct
include Printable.DefaultConf
let bot_name = "Dead code"
let top_name = "Totally unknown and messed up"
end) (LD)
let unlift x =
match x with
| `Lifted x -> x
| _ -> raise Deadcode
let printXml f = function
| `Top -> BatPrintf.fprintf f "<value>%s</value>" (XmlUtil.escape Printable.DefaultConf.top_name)
| `Bot -> ()
| `Lifted x -> LD.printXml f x
end
(** Man(ager) is passed to transfer functions and offers access to various facilities, e.g., to access the local state, the context,
read values from globals, side-effect values to globals and trigger events. *)
type ('d,'g,'c,'v) man =
{ ask : 'a. 'a Queries.t -> 'a Queries.result (* Inlined Queries.ask *)
; emit : Events.t -> unit
; node : MyCFG.node
; prev_node: MyCFG.node
; control_context : unit -> ControlSpecC.t (** top-level Control Spec context, raises [Man_failure] if missing *)
; context : unit -> 'c (** current Spec context, raises [Man_failure] if missing *)
; edge : MyCFG.edge
; local : 'd
; global : 'v -> 'g
; spawn : ?multiple:bool -> lval option -> varinfo -> exp list -> unit
; split : 'd -> Events.t list -> unit
; sideg : 'v -> 'g -> unit
}
exception Man_failure of string
(** Failure from man, e.g. global initializer *)
let man_failwith s = raise (Man_failure s) (* TODO: use everywhere in man *)
(** Convert [man] to [Queries.ask]. *)
let ask_of_man man: Queries.ask = { Queries.f = man.ask }
module type Spec =
sig
module D : Lattice.S
module G : Lattice.S
module C : Printable.S
module V: SpecSysVar (** Global constraint variables. *)
module P: DisjointDomain.Representative with type elt := D.t (** Path-representative. *)
val name : unit -> string
(** Auxiliary data (outside of solution domains) that needs to be marshaled and unmarshaled.
This includes:
* hashtables,
* varinfos (create_var),
* RichVarinfos. *)
type marshal
(** Initialize using unmarshaled auxiliary data (if present). *)
val init : marshal option -> unit
(** Finalize and return auxiliary data to be marshaled. *)
val finalize : unit -> marshal
(* val finalize : G.t -> unit *)
val startstate : varinfo -> D.t
val morphstate : varinfo -> D.t -> D.t
val exitstate : varinfo -> D.t
val context: (D.t, G.t, C.t, V.t) man -> fundec -> D.t -> C.t
val startcontext: unit -> C.t
val sync : (D.t, G.t, C.t, V.t) man -> [`Normal | `Join | `JoinCall of CilType.Fundec.t | `Return] -> D.t
val query : (D.t, G.t, C.t, V.t) man -> 'a Queries.t -> 'a Queries.result
(** A transfer function which handles the assignment of a rval to a lval, i.e.,
it handles program points of the form "lval = rval;" *)
val assign: (D.t, G.t, C.t, V.t) man -> lval -> exp -> D.t
(** A transfer function used for declaring local variables.
By default only for variable-length arrays (VLAs). *)
val vdecl : (D.t, G.t, C.t, V.t) man -> varinfo -> D.t
(** A transfer function which handles conditional branching yielding the
truth value passed as a boolean argument *)
val branch: (D.t, G.t, C.t, V.t) man -> exp -> bool -> D.t
(** A transfer function which handles going from the start node of a function (fundec) into
its function body. Meant to handle, e.g., initialization of local variables *)
val body : (D.t, G.t, C.t, V.t) man -> fundec -> D.t
(** A transfer function which handles the return statement, i.e.,
"return exp" or "return" in the passed function (fundec) *)
val return: (D.t, G.t, C.t, V.t) man -> exp option -> fundec -> D.t
(** A transfer function meant to handle inline assembler program points *)
val asm : (D.t, G.t, C.t, V.t) man -> D.t
(** A transfer function which works as the identity function, i.e., it skips and does nothing.
Used for empty loops. *)
val skip : (D.t, G.t, C.t, V.t) man -> D.t
(** A transfer function which, for a call to a {e special} function f "lval = f(args)" or "f(args)",
computes the caller state after the function call *)
val special : (D.t, G.t, C.t, V.t) man -> lval option -> varinfo -> exp list -> D.t
(** For a function call "lval = f(args)" or "f(args)",
[enter] returns a caller state, and the initial state of the callee.
In [enter], the caller state can usually be returned unchanged, as [combine_env] and [combine_assign] (below)
will compute the caller state after the function call, given the return state of the callee *)
val enter : (D.t, G.t, C.t, V.t) man -> lval option -> fundec -> exp list -> (D.t * D.t) list
(* Combine is split into two steps: *)
(** Combine environment (global variables, mutexes, etc)
between local state (first component from enter) and function return.
This shouldn't yet assign to the lval. *)
val combine_env : (D.t, G.t, C.t, V.t) man -> lval option -> exp -> fundec -> exp list -> C.t option -> D.t -> Queries.ask -> D.t
(** Combine return value assignment
to local state (result from combine_env) and function return.
This should only assign to the lval. *)
val combine_assign : (D.t, G.t, C.t, V.t) man -> lval option -> exp -> fundec -> exp list -> C.t option -> D.t -> Queries.ask -> D.t
(* Paths as sets: I know this is ugly! *)
val paths_as_set : (D.t, G.t, C.t, V.t) man -> D.t list
(** Returns initial state for created thread. *)
val threadenter : (D.t, G.t, C.t, V.t) man -> multiple:bool -> lval option -> varinfo -> exp list -> D.t list
(** Updates the local state of the creator thread using initial state of created thread. *)
val threadspawn : (D.t, G.t, C.t, V.t) man -> multiple:bool -> lval option -> varinfo -> exp list -> (D.t, G.t, C.t, V.t) man -> D.t
val event : (D.t, G.t, C.t, V.t) man -> Events.t -> (D.t, G.t, C.t, V.t) man -> D.t
end
module type Spec2Spec = functor (S: Spec) -> Spec
module type MCPA =
sig
include Printable.S
val may_race: t -> t -> bool
val should_print: t -> bool (** Whether value should be printed in race output. *)
end
module type MCPSpec =
sig
include Spec
module A: MCPA
val access: (D.t, G.t, C.t, V.t) man -> Queries.access -> A.t
end
type increment_data = {
server: bool;
solver_data: Obj.t;
changes: CompareCIL.change_info;
(* Globals for which the constraint
system unknowns should be restarted *)
restarting: Goblint_constraint.VarQuery.t list;
}
module StdV =
struct
let is_write_only _ = false
end
module UnitV =
struct
include Printable.Unit
include StdV
end
module VarinfoV =
struct
include CilType.Varinfo (* TODO: or Basetype.Variables? *)
include StdV
end
module EmptyV =
struct
include Printable.Empty
include StdV
end
module UnitA =
struct
include Printable.Unit
let may_race _ _ = true
let should_print _ = false
end
module EmptyP =
struct
include Printable.Empty
let of_elt _ = failwith "EmptyP.of_elt: analysis cannot be path-sensitive"
end
module UnitP =
struct
include Printable.Unit
let of_elt _ = ()
end
module IdentityP (D: Lattice.S) =
struct
include D
let of_elt x = x
end
(** Relatively safe default implementations of some boring Spec functions. *)
module DefaultSpec =
struct
module G = Lattice.Unit
module V = EmptyV
module P = EmptyP
type marshal = unit
let init _ = ()
let finalize () = ()
(* no inits nor finalize -- only analyses like Mutex, Base, ... need
these to do postprocessing or other imperative hacks. *)
let vdecl man _ = man.local
let asm x =
M.msg_final Info ~category:Unsound "ASM ignored";
M.info ~category:Unsound "ASM statement ignored.";
x.local (* Just ignore. *)
let skip x = x.local (* Just ignore. *)
let query _ (type a) (q: a Queries.t) = Queries.Result.top q
(* Don't know anything --- most will want to redefine this. *)
let event man _ _ = man.local
let morphstate v d = d
(* Only for those who track thread IDs. *)
let sync man _ = man.local
(* Most domains do not have a global part. *)
let context man fd x = x
(* Everything is context sensitive --- override in MCP and maybe elsewhere*)
let paths_as_set man = [man.local]
module A = UnitA
let access _ _ = ()
end
(* Even more default implementations. Most transfer functions acting as identity functions. *)
module IdentitySpec =
struct
include DefaultSpec
let assign man (lval:lval) (rval:exp) =
man.local
let branch man (exp:exp) (tv:bool) =
man.local
let body man (f:fundec) =
man.local
let return man (exp:exp option) (f:fundec) =
man.local
let enter man (lval: lval option) (f:fundec) (args:exp list) =
[man.local, man.local]
let combine_env man (lval:lval option) fexp (f:fundec) (args:exp list) fc au (f_ask: Queries.ask) =
au
let combine_assign man (lval:lval option) fexp (f:fundec) (args:exp list) fc au (f_ask: Queries.ask) =
man.local
let special man (lval: lval option) (f:varinfo) (arglist:exp list) =
man.local
let threadenter man ~multiple lval f args = [man.local]
let threadspawn man ~multiple lval f args fman = man.local
end
module IdentityUnitContextsSpec = struct
include IdentitySpec
module C = Printable.Unit
let context man _ _ = ()
let startcontext () = ()
end
module ValueContexts (D:Lattice.S) = struct
module C = D
let startcontext () = D.bot ()
end
module type SpecSys =
sig
module Spec: Spec
module EQSys: Goblint_constraint.ConstrSys.DemandGlobConstrSys with module LVar = VarF (Spec.C)
and module GVar = GVarF (Spec.V)
and module D = Spec.D
and module G = GVarG (Spec.G) (Spec.C)
module LHT: BatHashtbl.S with type key = EQSys.LVar.t
module GHT: BatHashtbl.S with type key = EQSys.GVar.t
end
module type SpecSysSol =
sig
module SpecSys: SpecSys
open SpecSys
val gh: EQSys.G.t GHT.t
val lh: SpecSys.Spec.D.t LHT.t (* explicit SpecSys to avoid spurious module cycle *)
end