package pds-reachability

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file pds_reachability_structure.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
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
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
(**
   This module defines a data structure used in a PDS reachability analysis.
*)
open Batteries;;
open Jhupllib;;
open Pds_reachability_utils;;

(**
   The type of the module which defines the data structure used within the
   analysis.
*)
module type Structure =
sig
  (** The decorated stack element type used by the PDS. *)
  module Stack_element : Decorated_type

  (** The decorated node type in the reachability structure. *)
  module Node : Decorated_type

  (** The decorated edge type in the reachability structure. *)
  module Edge : Decorated_type

  (** The decorated type of targeted dynamic pop actions in this structure. *)
  module Targeted_dynamic_pop_action : Decorated_type

  (** The decorated type of untargeted dynamic pop actions in this structure. *)
  module Untargeted_dynamic_pop_action : Decorated_type

  (** The type of the PDS reachability data structure. *)
  include Decorated_type

  (**
     Produces a Yojson structure representing the contents of a latter analysis
     which do not appear in the former.
  *)
  val to_yojson_delta : t -> t -> Yojson.Safe.t

  (** The empty PDS reachability structure. *)
  val empty : t

  (** Adds an edge to a reachability structure. *)
  val add_edge : Edge.t -> t -> t

  (** Determines if a structure has a particular edge. *)
  val has_edge : Edge.t -> t -> bool

  (** Adds an untargeted dynamic pop action to a reachability structure. *)
  val add_untargeted_dynamic_pop_action :
    Node.t -> Untargeted_dynamic_pop_action.t -> t -> t

  (** Determines if a given untargeted dynamic pop action is present in a
      reachability structure. *)
  val has_untargeted_dynamic_pop_action :
    Node.t -> Untargeted_dynamic_pop_action.t -> t -> bool

  (** {6 Query functions.} *)

  val find_push_edges_by_source
    : Node.t -> t -> (Node.t * Stack_element.t) Enum.t
  val find_pop_edges_by_source
    : Node.t -> t -> (Node.t * Stack_element.t) Enum.t
  val find_nop_edges_by_source
    : Node.t -> t -> Node.t Enum.t
  val find_targeted_dynamic_pop_edges_by_source
    : Node.t -> t -> (Node.t * Targeted_dynamic_pop_action.t) Enum.t
  val find_untargeted_dynamic_pop_actions_by_source
    : Node.t -> t -> Untargeted_dynamic_pop_action.t Enum.t
  val find_push_edges_by_target
    : Node.t -> t -> (Node.t * Stack_element.t) Enum.t
  val find_pop_edges_by_target
    : Node.t -> t -> (Node.t * Stack_element.t) Enum.t
  val find_nop_edges_by_target
    : Node.t -> t -> Node.t Enum.t

  val enumerate_nodes : t -> Node.t Enum.t
  val enumerate_edges : t -> Edge.t Enum.t

  (** {6 Submodules.} *)

  module Node_set : Set.S with type elt = Node.t
end;;

module Make
    (Basis : Pds_reachability_basis.Basis)
    (Dph : Pds_reachability_types_stack.Dynamic_pop_handler
     with module Stack_element = Basis.Stack_element
      and module State = Basis.State)
    (Types : Pds_reachability_types.Types
     with module State = Basis.State
      and module Stack_element = Basis.Stack_element
      and module Targeted_dynamic_pop_action = Dph.Targeted_dynamic_pop_action
      and module Untargeted_dynamic_pop_action = Dph.Untargeted_dynamic_pop_action
    )
  : Structure
    with module Stack_element = Basis.Stack_element
     and module Edge = Types.Edge
     and module Node = Types.Node
     and module Targeted_dynamic_pop_action = Types.Targeted_dynamic_pop_action
     and module Untargeted_dynamic_pop_action =
           Types.Untargeted_dynamic_pop_action
=
struct
  module State = Basis.State;;
  module Stack_element = Basis.Stack_element;;
  module Edge = Types.Edge;;
  module Node = Types.Node;;
  module Targeted_dynamic_pop_action = Types.Targeted_dynamic_pop_action
  module Untargeted_dynamic_pop_action =
    Types.Untargeted_dynamic_pop_action
  ;;

  open Types;;
  open Types.Stack_action.T;;

  (********** Simple internal data structures. **********)

  type node_and_stack_element =
    Node.t * Stack_element.t
  [@@deriving eq, ord, show, to_yojson]
  ;;

  type node_and_targeted_dynamic_pop_action =
    Node.t * Targeted_dynamic_pop_action.t
  [@@deriving eq, ord, show, to_yojson]
  ;;

  (********** Substructure definitions. **********)

  module Node_set = Set.Make(Node);;

  module Node_and_stack_element =
  struct
    type t = node_and_stack_element;;
    let equal = equal_node_and_stack_element;;
    let compare = compare_node_and_stack_element;;
    let pp = pp_node_and_stack_element;;
    let show = show_node_and_stack_element;;
    let to_yojson = node_and_stack_element_to_yojson;;
  end;;

  module Node_and_targeted_dynamic_pop_action =
  struct
    type t = node_and_targeted_dynamic_pop_action;;
    let equal = equal_node_and_targeted_dynamic_pop_action;;
    let compare = compare_node_and_targeted_dynamic_pop_action;;
    let pp = pp_node_and_targeted_dynamic_pop_action;;
    let show = show_node_and_targeted_dynamic_pop_action;;
    let to_yojson = node_and_targeted_dynamic_pop_action_to_yojson;;
  end;;

  module Make_nice_multimap(K : Decorated_type)(V : Decorated_type) =
  struct
    module Impl = Multimap.Make(K)(V);;
    include Impl;;
    include Multimap_pp.Make(Impl)(K)(V);;
    include Multimap_to_yojson.Make(Impl)(K)(V);;
  end;;

  module Node_to_node_and_stack_element_multimap =
    Make_nice_multimap(Node)(Node_and_stack_element)
  ;;

  module Node_and_stack_element_to_node_multimap =
    Make_nice_multimap(Node_and_stack_element)(Node)
  ;;

  module Node_to_node_and_targeted_dynamic_pop_action_multimap =
    Make_nice_multimap(Node)(Node_and_targeted_dynamic_pop_action)
  ;;

  module Node_to_untargeted_dynamic_pop_action_multimap =
    Make_nice_multimap(Node)(Untargeted_dynamic_pop_action)
  ;;

  module Node_and_targeted_dynamic_pop_action_to_node_multimap =
    Make_nice_multimap(Node_and_targeted_dynamic_pop_action)(Node)
  ;;

  module Node_to_node_multimap =
    Make_nice_multimap(Node)(Node)
  ;;

  (********** The data structure itself. **********)

  (** The type of the PDS reachability graph data structure. *)
  type t =
    { push_edges_by_source : Node_to_node_and_stack_element_multimap.t
    ; pop_edges_by_source : Node_to_node_and_stack_element_multimap.t
    ; nop_edges_by_source : Node_to_node_multimap.t
    ; targeted_dynamic_pop_edges_by_source : Node_to_node_and_targeted_dynamic_pop_action_multimap.t
    ; untargeted_dynamic_pop_actions_by_source : Node_to_untargeted_dynamic_pop_action_multimap.t
    ; push_edges_by_target : Node_to_node_and_stack_element_multimap.t
    ; pop_edges_by_target : Node_to_node_and_stack_element_multimap.t
    ; nop_edges_by_target : Node_to_node_multimap.t
    ; push_edges_by_source_and_element : Node_and_stack_element_to_node_multimap.t
    ; pop_edges_by_source_and_element : Node_and_stack_element_to_node_multimap.t
    }
  [@@deriving show]
  ;;

  let compare x y =
    let c1 = Node_to_node_and_stack_element_multimap.compare
        x.push_edges_by_source y.push_edges_by_source
    in
    if c1 <> 0
    then c1
    else
      let c2 = Node_to_node_and_stack_element_multimap.compare
          x.pop_edges_by_source y.pop_edges_by_source
      in
      if c2 <> 0
      then c2
      else
        let c3 = Node_to_node_multimap.compare
            x.nop_edges_by_source y.nop_edges_by_source
        in
        if c3 <> 0
        then c3
        else
          let c4 =
            Node_to_node_and_targeted_dynamic_pop_action_multimap.compare
              x.targeted_dynamic_pop_edges_by_source
              y.targeted_dynamic_pop_edges_by_source
          in
          if c4 <> 0
          then c4
          else
            let c5 =
              Node_to_untargeted_dynamic_pop_action_multimap.compare
                x.untargeted_dynamic_pop_actions_by_source
                y.untargeted_dynamic_pop_actions_by_source
            in
            if c5 <> 0
            then c5
            else 0
  ;;
  let equal x y = compare x y == 0;;

  let to_yojson x =
    `Assoc
      [ ( "push_edges_by_source"
        , Node_to_node_and_stack_element_multimap.to_yojson
            x.push_edges_by_source
        )
      ; ( "pop_edges_by_source"
        , Node_to_node_and_stack_element_multimap.to_yojson
            x.pop_edges_by_source
        )
      ; ( "nop_edges_by_source"
        , Node_to_node_multimap.to_yojson x.nop_edges_by_source
        )
      ; ( "targeted_dynamic_pop_edges_by_source"
        , Node_to_node_and_targeted_dynamic_pop_action_multimap.to_yojson
            x.targeted_dynamic_pop_edges_by_source
        )
      ; ( "untargeted_dynamic_pop_actions_by_source"
        , Node_to_untargeted_dynamic_pop_action_multimap.to_yojson
            x.untargeted_dynamic_pop_actions_by_source
        )
      ]
  ;;

  let to_yojson_delta x y =
    let multimap_delta enum of_enum mem x y =
      y
      |> enum
      |> Enum.filter
        (fun (k,v) -> not @@ mem k v x)
      |> of_enum
    in
    `Assoc
      (List.filter
         (fun (_,v) ->
            match v with
            | `List n -> not @@ List.is_empty n
            | _ -> true
         )
         [ ( "push_edges_by_source"
           , Node_to_node_and_stack_element_multimap.to_yojson @@
             multimap_delta
               Node_to_node_and_stack_element_multimap.enum
               Node_to_node_and_stack_element_multimap.of_enum
               Node_to_node_and_stack_element_multimap.mem
               x.push_edges_by_source y.push_edges_by_source
           )
         ; ( "pop_edges_by_source"
           , Node_to_node_and_stack_element_multimap.to_yojson @@
             multimap_delta
               Node_to_node_and_stack_element_multimap.enum
               Node_to_node_and_stack_element_multimap.of_enum
               Node_to_node_and_stack_element_multimap.mem
               x.pop_edges_by_source y.pop_edges_by_source
           )
         ; ( "nop_edges_by_source"
           , Node_to_node_multimap.to_yojson @@
             multimap_delta
               Node_to_node_multimap.enum
               Node_to_node_multimap.of_enum
               Node_to_node_multimap.mem
               x.nop_edges_by_source y.nop_edges_by_source
           )
         ; ( "targeted_dynamic_pop_edges_by_source"
           , Node_to_node_and_targeted_dynamic_pop_action_multimap.to_yojson @@
             multimap_delta
               Node_to_node_and_targeted_dynamic_pop_action_multimap.enum
               Node_to_node_and_targeted_dynamic_pop_action_multimap.of_enum
               Node_to_node_and_targeted_dynamic_pop_action_multimap.mem
               x.targeted_dynamic_pop_edges_by_source
               y.targeted_dynamic_pop_edges_by_source
           )
         ; ( "untargeted_dynamic_pop_actions_by_source"
           , Node_to_untargeted_dynamic_pop_action_multimap.to_yojson @@
             multimap_delta
               Node_to_untargeted_dynamic_pop_action_multimap.enum
               Node_to_untargeted_dynamic_pop_action_multimap.of_enum
               Node_to_untargeted_dynamic_pop_action_multimap.mem
               x.untargeted_dynamic_pop_actions_by_source
               y.untargeted_dynamic_pop_actions_by_source
           )
         ]
      )
  ;;

  let empty =
    { push_edges_by_source = Node_to_node_and_stack_element_multimap.empty
    ; pop_edges_by_source = Node_to_node_and_stack_element_multimap.empty
    ; nop_edges_by_source = Node_to_node_multimap.empty
    ; targeted_dynamic_pop_edges_by_source =
        Node_to_node_and_targeted_dynamic_pop_action_multimap.empty
    ; untargeted_dynamic_pop_actions_by_source =
        Node_to_untargeted_dynamic_pop_action_multimap.empty
    ; push_edges_by_target = Node_to_node_and_stack_element_multimap.empty
    ; pop_edges_by_target = Node_to_node_and_stack_element_multimap.empty
    ; nop_edges_by_target = Node_to_node_multimap.empty
    ; push_edges_by_source_and_element = Node_and_stack_element_to_node_multimap.empty
    ; pop_edges_by_source_and_element = Node_and_stack_element_to_node_multimap.empty
    };;

  let has_edge edge analysis =
    match edge.edge_action with
    | Nop ->
      analysis.nop_edges_by_source
      |> Node_to_node_multimap.mem edge.source edge.target
    | Push element ->
      analysis.push_edges_by_source_and_element
      |> Node_and_stack_element_to_node_multimap.mem
        (edge.source, element) edge.target
    | Pop element ->
      analysis.pop_edges_by_source_and_element
      |> Node_and_stack_element_to_node_multimap.mem
        (edge.source, element) edge.target
    | Pop_dynamic_targeted action ->
      analysis.targeted_dynamic_pop_edges_by_source
      |> Node_to_node_and_targeted_dynamic_pop_action_multimap.mem
        edge.source (edge.target, action)
  ;;

  let add_edge edge structure =
    match edge.edge_action with
    | Nop ->
      { structure with
        nop_edges_by_source =
          structure.nop_edges_by_source
          |> Node_to_node_multimap.add edge.source edge.target
      ; nop_edges_by_target =
          structure.nop_edges_by_target
          |> Node_to_node_multimap.add edge.target edge.source
      }
    | Push element ->
      { structure with
        push_edges_by_source =
          structure.push_edges_by_source
          |> Node_to_node_and_stack_element_multimap.add edge.source
            (edge.target, element)
      ; push_edges_by_target =
          structure.push_edges_by_target
          |> Node_to_node_and_stack_element_multimap.add edge.target
            (edge.source, element)
      ; push_edges_by_source_and_element =
          structure.push_edges_by_source_and_element
          |> Node_and_stack_element_to_node_multimap.add
            (edge.source, element) edge.target
      }
    | Pop element ->
      { structure with
        pop_edges_by_source =
          structure.pop_edges_by_source
          |> Node_to_node_and_stack_element_multimap.add edge.source
            (edge.target, element)
      ; pop_edges_by_target =
          structure.pop_edges_by_target
          |> Node_to_node_and_stack_element_multimap.add edge.target
            (edge.source, element)
      ; pop_edges_by_source_and_element =
          structure.pop_edges_by_source_and_element
          |> Node_and_stack_element_to_node_multimap.add
            (edge.source, element) edge.target
      }
    | Pop_dynamic_targeted action ->
      { structure with
        targeted_dynamic_pop_edges_by_source =
          structure.targeted_dynamic_pop_edges_by_source
          |> Node_to_node_and_targeted_dynamic_pop_action_multimap.add
            edge.source (edge.target, action)
      }
  ;;

  let add_untargeted_dynamic_pop_action source action structure =
    { structure with
      untargeted_dynamic_pop_actions_by_source =
        structure.untargeted_dynamic_pop_actions_by_source
        |> Node_to_untargeted_dynamic_pop_action_multimap.add
          source action
    }
  ;;

  let has_untargeted_dynamic_pop_action source action structure =
    structure.untargeted_dynamic_pop_actions_by_source
    |> Node_to_untargeted_dynamic_pop_action_multimap.mem source action
  ;;

  let find_push_edges_by_source source structure =
    Node_to_node_and_stack_element_multimap.find
      source structure.push_edges_by_source
  ;;

  let find_pop_edges_by_source source structure =
    Node_to_node_and_stack_element_multimap.find
      source structure.pop_edges_by_source
  ;;

  let find_nop_edges_by_source source structure =
    Node_to_node_multimap.find source structure.nop_edges_by_source
  ;;

  let find_targeted_dynamic_pop_edges_by_source source structure =
    Node_to_node_and_targeted_dynamic_pop_action_multimap.find source
      structure.targeted_dynamic_pop_edges_by_source
  ;;

  let find_untargeted_dynamic_pop_actions_by_source source structure =
    Node_to_untargeted_dynamic_pop_action_multimap.find source
      structure.untargeted_dynamic_pop_actions_by_source
  ;;

  let find_push_edges_by_target target structure =
    Node_to_node_and_stack_element_multimap.find
      target structure.push_edges_by_target
  ;;

  let find_pop_edges_by_target target structure =
    Node_to_node_and_stack_element_multimap.find
      target structure.pop_edges_by_target
  ;;

  let find_nop_edges_by_target target structure =
    Node_to_node_multimap.find target structure.nop_edges_by_target
  ;;

  let enumerate_nodes structure =
    Node_set.enum @@ Node_set.of_enum @@ Enum.concat @@ List.enum
      [ Node_to_node_and_stack_element_multimap.keys
          structure.push_edges_by_source
      ; Node_to_node_and_stack_element_multimap.keys
          structure.pop_edges_by_source
      ; Node_to_node_multimap.keys
          structure.nop_edges_by_source
      ; Node_to_node_and_targeted_dynamic_pop_action_multimap.keys
          structure.targeted_dynamic_pop_edges_by_source
      ; Node_to_untargeted_dynamic_pop_action_multimap.keys
          structure.untargeted_dynamic_pop_actions_by_source
      ; Node_to_node_and_stack_element_multimap.keys
          structure.push_edges_by_target
      ; Node_to_node_and_stack_element_multimap.keys
          structure.pop_edges_by_target
      ; Node_to_node_multimap.keys
          structure.nop_edges_by_target
      ; Enum.map (fst % snd)
          (Node_to_node_and_targeted_dynamic_pop_action_multimap.enum
             structure.targeted_dynamic_pop_edges_by_source)
      ]
  ;;

  let enumerate_edges structure =
    Enum.concat @@ List.enum
      [ Node_to_node_and_stack_element_multimap.enum
          structure.push_edges_by_source
        |> Enum.map
          (fun (source,(target,element)) ->
             { source = source
             ; target = target
             ; edge_action = Push element
             })
      ; Node_to_node_and_stack_element_multimap.enum
          structure.pop_edges_by_source
        |> Enum.map
          (fun (source,(target,element)) ->
             { source = source
             ; target = target
             ; edge_action = Pop element
             })
      ; Node_to_node_multimap.enum
          structure.nop_edges_by_source
        |> Enum.map
          (fun (source,target) ->
             { source = source
             ; target = target
             ; edge_action = Nop
             })
      ; Node_to_node_and_targeted_dynamic_pop_action_multimap.enum
          structure.targeted_dynamic_pop_edges_by_source
        |> Enum.map
          (fun (source,(target,dynamic_pop)) ->
             { source = source
             ; target = target
             ; edge_action = Pop_dynamic_targeted dynamic_pop
             })
      ]
  ;;
end;;
OCaml

Innovation. Community. Security.