package mopsa

  1. Overview
  2. Docs
MOPSA: A Modular and Open Platform for Static Analysis using Abstract Interpretation

Install

Dune Dependency

Authors

Maintainers

Sources

mopsa-analyzer-v1.1.tar.gz
md5=fdee20e988343751de440b4f6b67c0f4
sha512=f5cbf1328785d3f5ce40155dada2d95e5de5cce4f084ea30cfb04d1ab10cc9403a26cfb3fa55d0f9da72244482130fdb89c286a9aed0d640bba46b7c00e09500

doc/src/lattices/pointwise.ml.html

Source file pointwise.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
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
(****************************************************************************)
(*                                                                          *)
(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)
(*                                                                          *)
(* Copyright (C) 2017-2019 The MOPSA Project.                               *)
(*                                                                          *)
(* This program is free software: you can redistribute it and/or modify     *)
(* it under the terms of the GNU Lesser General Public License as published *)
(* by the Free Software Foundation, either version 3 of the License, or     *)
(* (at your option) any later version.                                      *)
(*                                                                          *)
(* This program is distributed in the hope that it will be useful,          *)
(* but WITHOUT ANY WARRANTY; without even the implied warranty of           *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *)
(* GNU Lesser General Public License for more details.                      *)
(*                                                                          *)
(* You should have received a copy of the GNU Lesser General Public License *)
(* along with this program.  If not, see <http://www.gnu.org/licenses/>.    *)
(*                                                                          *)
(****************************************************************************)

(** Pointwise lattice construction.

    Lattice of partial maps 𝕂 ⇀ 𝕍 where 𝕂 is a key set 
    and 𝕍 is a value lattice.
    Unlink Partial_map, ⊥ values is not coalescent.

    Bindings that map keys to ⊥ values are not represented.    

    We use Maps, so 𝕂 needs to be totally ordered.

    ⊥ map is represented as the empty map.
    ⊤ map is represented as a special TOP element.
*)

open Mopsa_utils
open Top
open Core.All


let debug fmt = Debug.debug ~channel:"framework.lattices.pointwise" fmt

module type KEY =
sig
  type t
  val compare: t -> t -> int
  val print : printer -> t -> unit
end


module Make
    (Key   : KEY)
    (Value : LATTICE)
=
struct

  module M = MapExt.Make(Key)

  type nt_t = Value.t M.t

  type t = nt_t with_top

  let bottom : t = Nt M.empty

  let empty : t = bottom
  
  let top : t = TOP

  let is_bottom (a:t) : bool = 
    top_dfl1 false M.is_empty a

  let is_empty (a:t) : bool =
    is_bottom a

  let is_top (a:t) : bool =
    a = TOP
  
  let subset (a:t) (b:t) : bool =
    if a == b then true else
    top_included
      (M.for_all2zo
         (fun _ _ -> false)
         (fun _ _ -> true)
         (fun _ x y -> Value.subset x y))
      a b

  let join (a:t) (b:t) : t =
    if a == b then a else
    top_lift2
      (M.map2zo
         (fun _ x -> x)
         (fun _ x -> x)
         (fun _ x y -> Value.join x y)
      )
      a b
  
  let widen ctx (a:t) (b:t) : t =
    if a == b then a else
    top_lift2
      (M.map2zo
         (fun _ x -> x)
         (fun _ x -> x)
         (fun _ x y -> Value.widen ctx x y)
      )
      a b

  let meet (a:t) (b:t) : t =
    if a == b then a else
    top_neutral2
      (M.map2zo
         (fun _ x -> x)
         (fun _ x -> x)
         (fun _ x y -> Value.meet x y)
      )
      a b

  let print printer (a:t) : unit =
    match a with
    | TOP -> pp_string printer "⊤"
    | Nt m when M.is_empty m -> pp_string printer "⊥"
    | Nt m ->
      pp_map
        Key.print Value.print
        printer (M.bindings m)

  (** Returns ⊥ value if either k is not found, or a is the ⊤ map. *)
  let find (k: Key.t) (a:t) : Value.t =
    top_dfl1
      Value.top
      (fun m -> try M.find k m with Not_found -> Value.bottom) a

  let remove (k: Key.t) (a:t) : t =
    top_lift1 (fun m -> M.remove k m) a

  (* Internal function .
     Call this instead of M.add to ensure that no binding to the ⊥ value
     is ever added to the map.
  *)
  let m_add (k: Key.t) (v:Value.t) (a:nt_t) : nt_t =
    if Value.is_bottom v then M.remove k a else M.add k v a
    
  let add (k: Key.t) (v:Value.t) (a:t) : t =
    top_lift1 (fun m -> m_add k v m) a

  (** Returns false of a is the ⊤ map, or k is mapped to the ⊥ value. *)
  let mem (k: Key.t) (a:t) : bool =
    top_dfl1 false (M.mem k) a
  
  let rename (k: Key.t) (k': Key.t) (a:t) : t =
    let v = find k a in
    let a = remove k a in
    add k' v a

  let apply (k: Key.t) (f:Value.t -> Value.t) (a:t) : t =
    add k (f (find k a)) a
  
  let singleton (k:Key.t) (v:Value.t) : t =
    add k v bottom

  let filter (f : Key.t -> Value.t -> bool) (a :t) : t =
    top_lift1 (M.filter f) a

  
  (** Raises a Top_encountered exception for the ⊤ map. *)
  let bindings (a:t) : (Key.t * Value.t) list =
    M.bindings (detop a)

  
  (** Returns None for a ⊤ or ⊥ map. *)
  let max_binding (a:t) : (Key.t * Value.t) option =
    top_dfl1
      None
      (fun m -> try Some (M.max_binding m) with Not_found -> None)
      a

  (** Raises a Top_encountered exception for the ⊤ map. *)
  let cardinal (a:t) : int =
    M.cardinal (detop a)

  let of_list (l : (Key.t * Value.t) list) : t =
    Nt (M.of_list l)



  (** Iterator functions.
  
      These functions do nothing for the ⊤ map, which is 
      equivalent here to the empty map.
  *)
      
  let iter (f:Key.t -> Value.t -> unit) (a:t) : unit =
    top_apply (M.iter f) () a

  let fold (f:Key.t -> Value.t -> 'a -> 'a) (a:t) (x:'a) : 'a =
    top_dfl1 x (fun a -> M.fold f a x) a

  let map (f:Value.t -> Value.t) (a:t) : t =
    top_lift1 (fun m -> M.fold (fun k v n -> m_add k (f v) n) m M.empty) a

  let mapi (f:Key.t -> Value.t -> Value.t) (a:t) : t =
    top_lift1 (fun m -> M.fold (fun k v n -> m_add k (f k v) n) m M.empty) a

  let for_all (f:Key.t -> Value.t -> bool) (a:t) : bool =
    top_dfl1 false (M.for_all f) a

  let exists (f:Key.t -> Value.t -> bool) (a:t) : bool =
    top_dfl1 false (M.exists f) a



  (**
     Binary iterators.

     If a key is bound in only one map, the function is called
     with the ⊥ value as missing argument.
     These functions do nothing if either map is the ⊤ map.     
  *)
  
  let map2 (f:Key.t -> Value.t -> Value.t -> Value.t) (m1:t) (m2:t) : t =
    top_lift2
      (fun m1 m2 ->
         M.fold2o
           (fun k v1 n -> m_add k (f k v1 Value.bottom) n)
           (fun k v2 n -> m_add k (f k Value.bottom v2) n)
           (fun k v1 v2 n -> m_add k (f k v1 v2) n)
           m1 m2 M.empty
      )
      m1 m2

  let iter2 (f:Key.t -> Value.t -> Value.t -> unit) (m1:t) (m2:t) : unit =
    top_apply2
      () ()
      (M.iter2o
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f)
      m1 m2

  let fold2 (f:Key.t -> Value.t -> Value.t -> 'a -> 'a) (m1:t) (m2:t) (acc:'a) : 'a =
    top_apply2
      acc acc
      (fun m1 m2 ->
         M.fold2o
           (fun k v1 acc -> f k v1 Value.bottom acc)
           (fun k v2 acc -> f k Value.bottom v2 acc)
           f
           m1 m2 acc
      )
      m1 m2

  let for_all2 (f:Key.t -> Value.t -> Value.t -> bool) (m1:t) (m2:t) : bool =
    top_dfl2
      false
      (M.for_all2o
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f
      )
      m1 m2

  let exists2 (f:Key.t -> Value.t -> Value.t -> bool) (m1:t) (m2:t) : bool =
    top_dfl2
      false
      (M.exists2o
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f
      )
      m1 m2


  let map2z (f:Key.t -> Value.t -> Value.t -> Value.t) (m1:t) (m2:t) : t =
    top_lift2
      (fun m1 m2 ->
         M.fold2zo
           (fun k v1 n -> m_add k (f k v1 Value.bottom) n)
           (fun k v2 n -> m_add k (f k Value.bottom v2) n)
           (fun k v1 v2 n -> m_add k (f k v1 v2) n)
           m1 m2 M.empty
      )
      m1 m2

  let iter2z (f:Key.t -> Value.t -> Value.t -> unit) (m1:t) (m2:t) : unit =
    top_apply2
      () ()
      (M.iter2zo
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f)
      m1 m2

  let fold2z (f:Key.t -> Value.t -> Value.t -> 'a -> 'a) (m1:t) (m2:t) (acc:'a) : 'a =
    top_apply2
      acc acc
      (fun m1 m2 ->
         M.fold2z
           f
           m1 m2 acc
      )
      m1 m2

  let fold2zo
      (f1:Key.t -> Value.t -> 'a -> 'a)
      (f2:Key.t -> Value.t -> 'a -> 'a)
      (f:Key.t -> Value.t -> Value.t -> 'a -> 'a) (m1:t) (m2:t) (acc:'a) : 'a =
    top_apply2
      acc acc
      (fun m1 m2 ->
         M.fold2zo f1 f2 f m1 m2 acc
      )
      m1 m2

  let for_all2z (f:Key.t -> Value.t -> Value.t -> bool) (m1:t) (m2:t) : bool =
    top_dfl2
      false
      (M.for_all2zo
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f
      )
      m1 m2

  let exists2z (f:Key.t -> Value.t -> Value.t -> bool) (m1:t) (m2:t) : bool =
    top_dfl2
      false
      (M.exists2zo
         (fun k v1 -> f k v1 Value.bottom)
         (fun k v2 -> f k Value.bottom v2)
         f
      )
      m1 m2


  

  (** Slice iterations. *)
  

  let map_slice (f:Key.t -> Value.t -> Value.t) (m:t) (lo:Key.t) (hi:Key.t) : t =
    top_lift1 (fun m -> M.fold_slice (fun k v n -> m_add k (f k v) n) m lo hi M.empty) m

  let iter_slice (f:Key.t -> Value.t -> unit) (m:t) (lo:Key.t) (hi:Key.t) : unit =
    top_apply (fun m -> M.iter_slice f m lo hi) () m
      
  let fold_slice (f:Key.t -> Value.t -> 'a -> 'a) (m:t) (lo:Key.t) (hi:Key.t) (acc:'a) : 'a =
    top_apply (fun m -> M.fold_slice f m lo hi acc) acc m

  let for_all_slice (f:Key.t -> Value.t -> bool) (m:t) (lo:Key.t) (hi:Key.t) : bool =
    top_dfl1 false (fun m -> M.for_all_slice f m lo hi) m

  let exists_slice (f:Key.t -> Value.t -> bool) (m:t) (lo:Key.t) (hi:Key.t) : bool =
    top_dfl1 false (fun m -> M.exists_slice f m lo hi) m
  
end
OCaml

Innovation. Community. Security.