-
Notifications
You must be signed in to change notification settings - Fork 77
/
Copy pathoffset.ml
265 lines (220 loc) · 8.59 KB
/
offset.ml
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
include Offset_intf
open GoblintCil
module M = Messages
module Index =
struct
include Index
module Unit: Printable with type t = unit =
struct
include Lattice.UnitConf (struct let name = "?" end)
let name () = "unit index"
let equal_to _ _ = `Top
let to_int _ = None
end
module Exp =
struct
include CilType.Exp
let name () = "exp index"
let any = Cilfacade.any_index_exp
let all = CastE (TInt (Cilfacade.ptrdiff_ikind (), []), mkString "all_index")
(* Override output *)
let pretty () x =
if equal x any then
Pretty.text "?"
else
dn_exp () x
include Printable.SimplePretty (
struct
type nonrec t = t
let pretty = pretty
end
)
let equal_to _ _ = `Top (* TODO: more precise for definite indices *)
let to_int _ = None (* TODO: more precise for definite indices *)
let top () = any
end
end
module MakePrintable (Idx: Index.Printable): Printable with type idx = Idx.t =
struct
type idx = Idx.t
type t = Idx.t offs [@@deriving eq, ord, hash]
include Printable.StdLeaf
let name () = Format.sprintf "offset (%s)" (Idx.name ())
let rec cmp_zero_offset : t -> [`MustZero | `MustNonzero | `MayZero] = function
| `NoOffset -> `MustZero
| `Index (x, o) ->
begin match cmp_zero_offset o, Idx.equal_to (IntOps.BigIntOps.zero) x with
| `MustNonzero, _
| _, `Neq -> `MustNonzero
| `MustZero, `Eq -> `MustZero
| _, _ -> `MayZero
end
| `Field (x, o) ->
if Cilfacade.is_first_field x then cmp_zero_offset o else `MustNonzero
let rec show: t -> string = function
| `NoOffset -> ""
| `Index (x,o) -> "[" ^ (Idx.show x) ^ "]" ^ (show o)
| `Field (x,o) -> "." ^ (x.fname) ^ (show o)
include Printable.SimpleShow (
struct
type nonrec t = t
let show = show
end
)
let rec is_definite: t -> bool = function
| `NoOffset -> true
| `Field (f,o) -> is_definite o
| `Index (i,o) -> Idx.to_int i <> None && is_definite o
(* append offset o2 to o1 *)
let rec add_offset (o1: t) (o2: t): t =
match o1 with
| `NoOffset -> o2
| `Field (f1,o1) -> `Field (f1,add_offset o1 o2)
| `Index (i1,o1) -> `Index (i1,add_offset o1 o2)
let rec remove_offset: t -> t = function
| `NoOffset -> `NoOffset
| `Index (_,`NoOffset) | `Field (_,`NoOffset) -> `NoOffset
| `Index (i,o) -> `Index (i, remove_offset o)
| `Field (f,o) -> `Field (f, remove_offset o)
let rec to_cil_offset (x:t) = (* TODO: rename/move *)
match x with
| `NoOffset -> NoOffset
| `Field(f,o) -> Field(f, to_cil_offset o)
| `Index(i,o) -> NoOffset (* array domain can not deal with this -> leads to being handeled as access to unknown part *)
let rec to_exp: t -> exp offs = function
| `NoOffset -> `NoOffset
| `Index (i,o) ->
let i_exp = match Idx.to_int i with
| Some i -> Const (CInt (i, Cilfacade.ptrdiff_ikind (), Some (Z.to_string i)))
| None -> Index.Exp.any
in
`Index (i_exp, to_exp o)
| `Field (f,o) -> `Field (f, to_exp o)
let rec to_cil: t -> offset = function
| `NoOffset -> NoOffset
| `Index (i,o) ->
let i_exp = match Idx.to_int i with
| Some i -> Const (CInt (i, Cilfacade.ptrdiff_ikind (), Some (Z.to_string i)))
| None -> Index.Exp.any
in
Index (i_exp, to_cil o)
| `Field (f,o) -> Field (f, to_cil o)
let rec contains_index: t -> bool = function
| `NoOffset -> false
| `Field (_, os) -> contains_index os
| `Index _ -> true
let rec map_indices g: t -> t = function
| `NoOffset -> `NoOffset
| `Field (f, o) -> `Field (f, map_indices g o)
| `Index (i, o) -> `Index (g i, map_indices g o)
let top_indices = map_indices (fun _ -> Idx.top ())
(* tries to follow o in t *)
let rec type_of ~base:t o = match unrollType t, o with (* resolves TNamed *)
| t, `NoOffset -> t
| TArray (t,_,_), `Index (i,o)
| TPtr (t,_), `Index (i,o) -> type_of ~base:t o
| TComp (ci,_), `Field (f,o) ->
let fi = try getCompField ci f.fname
with Not_found -> raise (Type_of_error (t, show o))
in type_of ~base:fi.ftype o
(* TODO: Why? Imprecise on zstd-thread-pool regression tests. *)
(* | TComp _, `Index (_,o) -> type_of ~base:t o (* this happens (hmmer, perlbench). safe? *) *)
| t, o -> raise (Type_of_error (t, show o))
let rec prefix (x: t) (y: t): t option = match x,y with
| `Index (x, xs), `Index (y, ys) when Idx.equal x y -> prefix xs ys
| `Field (x, xs), `Field (y, ys) when CilType.Fieldinfo.equal x y -> prefix xs ys
| `NoOffset, ys -> Some ys
| _ -> None
end
module MakeLattice (Idx: Index.Lattice): Lattice with type idx = Idx.t =
struct
include MakePrintable (Idx)
let rec leq x y =
match x, y with
| `NoOffset, `NoOffset -> true
| `Index (i1,o1), `Index (i2,o2) when Idx.leq i1 i2 -> leq o1 o2
| `Field (f1,o1), `Field (f2,o2) when CilType.Fieldinfo.equal f1 f2 -> leq o1 o2
| _ -> false
let rec merge cop x y =
let op = match cop with `Join -> Idx.join | `Meet -> Idx.meet | `Widen -> Idx.widen | `Narrow -> Idx.narrow in
match x, y with
| `NoOffset, `NoOffset -> `NoOffset
| `Field (x1,y1), `Field (x2,y2) when CilType.Fieldinfo.equal x1 x2 -> `Field (x1, merge cop y1 y2)
| `Index (x1,y1), `Index (x2,y2) -> `Index (op x1 x2, merge cop y1 y2)
| _ -> raise Lattice.Uncomparable (* special case not used for AddressDomain any more due to splitting *)
let join x y = merge `Join x y
let meet x y = merge `Meet x y
let widen x y = merge `Widen x y
let narrow x y = merge `Narrow x y
(* NB! Currently we care only about concrete indexes. Base (seeing only a int domain
element) answers with any_index_exp on all non-concrete cases. *)
let rec of_exp: exp offs -> t = function
| `NoOffset -> `NoOffset
| `Index (Const (CInt (i,ik,s)),o) -> `Index (Idx.of_int ik i, of_exp o)
| `Index (_,o) -> `Index (Idx.top (), of_exp o)
| `Field (f,o) -> `Field (f, of_exp o)
let to_index ?typ (offs: t): Idx.t =
let idx_of_int x =
Idx.of_int (Cilfacade.ptrdiff_ikind ()) (Z.of_int x)
in
let rec offset_to_index_offset ?typ offs = match offs with
| `NoOffset -> idx_of_int 0
| `Field (field, o) ->
let field_as_offset = Field (field, NoOffset) in
let bits_offset, _size = GoblintCil.bitsOffset (TComp (field.fcomp, [])) field_as_offset in
let bits_offset = idx_of_int bits_offset in
let remaining_offset = offset_to_index_offset ~typ:field.ftype o in
Idx.add bits_offset remaining_offset
| `Index (x, o) ->
let (item_typ, item_size_in_bits) =
match Option.map unrollType typ with
| Some TArray(item_typ, _, _) ->
let item_size_in_bits = bitsSizeOf item_typ in
(Some item_typ, idx_of_int item_size_in_bits)
| _ ->
(None, Idx.top ())
in
let bits_offset = Idx.mul item_size_in_bits x in
let remaining_offset = offset_to_index_offset ?typ:item_typ o in
Idx.add bits_offset remaining_offset
in
offset_to_index_offset ?typ offs
let semantic_equal ~typ1 xoffs ~typ2 yoffs =
let x_index = to_index ~typ:typ1 xoffs in
let y_index = to_index ~typ:typ2 yoffs in
if M.tracing then M.tracel "addr" "xoffs=%a typ1=%a xindex=%a yoffs=%a typ2=%a yindex=%a\n" pretty xoffs d_plaintype typ1 Idx.pretty x_index pretty yoffs d_plaintype typ2 Idx.pretty y_index;
Idx.to_bool (Idx.eq x_index y_index)
include Lattice.NoBotTop
let pretty_diff () (x,y) =
Pretty.dprintf "%s: %a not equal %a" (name ()) pretty x pretty y
end
module Unit =
struct
include MakePrintable (Index.Unit)
(* TODO: rename to of_poly? *)
let rec of_offs: 'i offs -> t = function
| `NoOffset -> `NoOffset
| `Field (f,o) -> `Field (f, of_offs o)
| `Index (i,o) -> `Index ((), of_offs o)
let rec of_cil: offset -> t = function
| NoOffset -> `NoOffset
| Index (i,o) -> `Index ((), of_cil o)
| Field (f,o) -> `Field (f, of_cil o)
end
module Exp =
struct
include MakePrintable (Index.Exp)
let rec of_cil: offset -> t = function
| NoOffset -> `NoOffset
| Index (i,o) -> `Index (i, of_cil o)
| Field (f,o) -> `Field (f, of_cil o)
(* Overrides MakePrintable.to_cil. *)
let rec to_cil: t -> offset = function
| `NoOffset -> NoOffset
| `Index (i,o) -> Index (i, to_cil o)
| `Field (f,o) -> Field (f, to_cil o)
end
let () = Printexc.register_printer (function
| Type_of_error (t, o) -> Some (GobPretty.sprintf "Offset.Type_of_error(%a, %s)" d_plaintype t o)
| _ -> None (* for other exceptions *)
)