package codex

  1. Overview
  2. Docs
The Codex library for building static analysers based on abstract interpretation

Install

dune-project
 Dependency

Authors

Maintainers

Sources

1.0-rc4.tar.gz
md5=bc7266a140c6886add673ede90e335d3
sha512=8da42c0ff2c1098c5f9cb2b5b43b306faf7ac93b8f5ae00c176918cee761f249ff45b29309f31a05bbcf6312304f86a0d5a000eb3f1094d3d3c2b9b4c7f5c386

doc/src/codex.fixpoint/fixpoint_wto.ml.html

Source file fixpoint_wto.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
(**************************************************************************)
(*  This file is part of the Codex semantics library.                     *)
(*                                                                        *)
(*  Copyright (C) 2013-2025                                               *)
(*    CEA (Commissariat à l'énergie atomique et aux énergies              *)
(*         alternatives)                                                  *)
(*                                                                        *)
(*  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, version 2.1.                                              *)
(*                                                                        *)
(*  It 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.                   *)
(*                                                                        *)
(*  See the GNU Lesser General Public License version 2.1                 *)
(*  for more details (enclosed in the file LICENSE).                      *)
(*                                                                        *)
(**************************************************************************)

module Log = Tracelog.Make(struct let category = "Fixpoint.Fixpoint_Wto" end);;

module type AbstractDomain = sig
  type state
  type transition
  type loop_id
  val copy: state -> state
  val join: state -> state -> state
  val fixpoint_step: loop_id:loop_id -> state -> state -> (state * bool)
  val transfer: transition -> state -> state option
  val pp: Format.formatter -> state -> unit
  val enter_loop: state -> (state * loop_id)
  val leave_loop: state -> state
end


module type Graph = sig
  type transition
  module ControlLocation:PatriciaTree.KEY
  val preds_with_transition: ControlLocation.t -> (ControlLocation.t * transition) list
end

module Make(G:Graph)(D:AbstractDomain with type transition = G.transition) = struct

  module CLMap = PatriciaTree.MakeMap(G.ControlLocation);;

  (* Compute the prestate for a node. *)
  let pre node map =
    let preds = G.preds_with_transition node in
    let prestates = preds |> List.filter_map(fun (pred,transition) ->
        match CLMap.find pred map with
        | exception Not_found -> None
        | state -> D.transfer transition state) in
    match prestates with
    | [] -> None
    | a::b ->
      let state = List.fold_left D.join a b in
      Some state

  let pp_opt fmt x = match x with
    | None -> Format.fprintf fmt "None"
    | Some v -> Format.fprintf fmt "Some %a" D.pp v

  let pp_map fmt map =
    Format.fprintf fmt "{ ";
    map |> CLMap.iter (fun key _value -> Format.fprintf fmt "%d " (G.ControlLocation.to_int key));
    Format.fprintf fmt "} "
  ;;

  (* If node is a single node, update it in the map (remove the binding if the state is bottom. *)
  let update node value map =
    Log.debug (fun p -> p "Updating %d with %a %a" (G.ControlLocation.to_int node) pp_opt value pp_map map);
    match value with
    | None -> CLMap.remove node map
    | Some value -> CLMap.add node value map
  ;;

  let fixpoint_step ~loop_id previous next = match previous,next with
    | Some previous, Some next ->
      let state,bool = D.fixpoint_step ~loop_id previous next in
      Log.debug (fun p ->
          p "Fixpoint step@\n previous:@\n %a@\nnext:@\n %a@\nres:@\n%a"
            D.pp previous D.pp next D.pp state);
      Some state, bool
    | None, (Some _) -> next, false
    | None, None -> None, true
    | Some _, None -> assert false (* Should not happen if transfer
                                      functions are monotonous. *)

  let copy = Option.map D.copy

  (* Note: this assumes an initial map which is not changed after,
     i.e. we want the entry point to have no predecessor. TODO: check
     it. *)
  let rec fixpoint_component acc = function
    | Wto.Node n -> update n (pre n acc) acc
    | Wto.Component(head,part) ->
      (* We start over from save_acc everytime, otherwise we have
         spurious values when joining that come from the end of
         previous iterations. This strategy is described in [Lemerre,
         POPL 2023]. *)
      let save_acc = acc in
      let head_prestate = pre head acc in
      match head_prestate with
      | None -> acc             (* Nothing to propagate on this component. *)
      | Some head_prestate -> begin
        let head_prestate, loop_id = D.enter_loop head_prestate in
        let rec loop head_prestate =
          let head_prestate_backup = copy head_prestate in
          let acc = update head head_prestate acc in
          let acc = fixpoint_partition acc part in
          let new_head_prestate = pre head acc in
          let newstate, fp_reached = fixpoint_step ~loop_id head_prestate_backup new_head_prestate in
          Log.debug (fun p -> p "Fixpoint reached: %b" fp_reached);
          if fp_reached then
            (* We found an invariant on head. Perform one last,
               possibly descending, iteration, to continue and to
               register alarms in the loop. Note that this also
               performs localized widening
               [amato_scozzari2013localizing_widening_narrowing]. *)
            let newstate = Option.map (fun st -> D.leave_loop st) newstate in
            let acc = update head newstate save_acc in
            fixpoint_partition acc part
          else loop newstate
        in
        loop (Some head_prestate)
      end

  and fixpoint_partition acc list =
    List.fold_left fixpoint_component acc list

end