Release coccinelle-0.2.0rc1
[bpt/coccinelle.git] / engine / check_reachability.ml
CommitLineData
34e49164
C
1(* ---------------------------------------------------------------- *)
2(* code to check for ambiguities *)
3
4(* Idea: for each node that is said to be modified in any witness tree, we
5 check that all backward paths end up at the root of some witness tree
6 that says that the node should be modified. We then give a warning, if
7 the node itself appears more than once in such a path, because then there
8 could be some instances that are modified and some that are not. An
9 example is as follows:
10
11 f(); ... g(); ... - h();
12
13 with C code: f(); while(E) { h(); g(); } g(); h();
14
15 Then the h() in the while loop matches both the first ... and the - h();
16
17 Concretely, if a node 47 is in the witness tree rooted at 1 and the
18 witness tree rooted at 2, then we give an error if 47 is not in the set
19 of nodes satisfying AF[1v2] and give a warning if 47 is in the set of
20 nodes satisfying EXEF(47 & EXEF(1v2)). (Note that the root of a witness
21 tree here is the node causing the pattern to match; there might not be
22 any witnesses associated with this node.)
23
24 Another try on the exists formula:
25 !(1v2) & EXE[!(1v2) U 47]
26 The first !(1v2) is to discard immediately cases where the beginning and
27 end of the path are the same. Afterwards, it would only seem necessary to
28 serach up to the next occurrence of 47 (leaf), ensuring that there are not
29 1s or 2s (starting points) along the way. Then the second 47 would be in
30 the path, but possible not transformed.
31 *)
32
33module G = Ograph_extended
34module CTL = Ast_ctl
35
36(* Step 1: for each tree, make a mapping from the modified nodes to the root
37of the tree *)
38
39let modified = (Hashtbl.create(25) : (G.nodei, G.nodei list ref) Hashtbl.t)
40
41let build_modified (n,_,wits) =
42 let rec loop = function
43 CTL.Wit(st,[CTL.Subst(x,Wrapper_ctl.PredVal(CTL.Modif(v)))],anno,wit) ->
44 let cell =
45 try Hashtbl.find modified st
46 with Not_found ->
47 let cell = ref [] in Hashtbl.add modified st cell; cell in
48 cell := n :: !cell;
49 List.iter loop wit
50 | CTL.Wit(st,_,anno,wit) -> List.iter loop wit
51 | CTL.NegWit(wit) -> () in
52 List.iter loop wits
53
54(* Step 2: For each node in the hash table, create the error and warning
55 formulas *)
56
57type 'a nodes = Node of 'a | After
58
59let create_formulas _ =
60 Hashtbl.fold
61 (function node ->
62 function roots ->
63 function acc ->
64 (*let exef f =
65 wrap
66 (Ast_ctl.EX
67 (Ast_ctl.BACKWARD,wrap(Ast_ctl.EF(Ast_ctl.BACKWARD,f)))) in*)
68 let match_node = Ast_ctl.Pred(Node(node)) in
69 let match_roots =
70 List.map (function n -> Ast_ctl.Pred(Node(n)))
71 (List.sort compare !roots) in
72 let roots =
73 List.fold_left
74 (function prev -> function cur -> Ast_ctl.Or(prev,cur))
75 (List.hd match_roots) (List.tl match_roots) in
76 (node,
77 Ast_ctl.AF(Ast_ctl.BACKWARD,Ast_ctl.NONSTRICT,
78 Ast_ctl.Or(roots,Ast_ctl.Pred(After))),
79 Ast_ctl.And
80 (Ast_ctl.NONSTRICT,
81 Ast_ctl.Not(roots),
82 Ast_ctl.EX
83 (Ast_ctl.BACKWARD,
84 Ast_ctl.EU(Ast_ctl.BACKWARD,roots,match_node))))
85 (*exef
86 (wrap(Ast_ctl.And(Ast_ctl.NONSTRICT,match_node,exef(roots))))*)
87 :: acc)
88 modified []
89
90(* Step 3: check the formula on the control-flow graph *)
91
92module PRED =
93 struct
94 type t = Ograph_extended.nodei nodes
95 let print_predicate = function
96 After -> Format.print_string "after"
97 | Node x -> Format.print_string (string_of_int x)
98 end
99
100module ENV =
101 struct
102 type value = unit
103 type mvar = unit
104 let eq_mvar x x' = failwith "should not be invoked"
105 let eq_val v v' = failwith "should not be invoked"
106 let merge_val v v' = failwith "should not be invoked"
107
108 let print_mvar s = failwith "should not be invoked"
109 let print_value x = failwith "should not be invoked"
110 end
111
112
113module CFG =
114 struct
115 type node = Ograph_extended.nodei
116 type cfg =
117 (Control_flow_c.node, Control_flow_c.edge)
118 Ograph_extended.ograph_mutable
119 let predecessors cfg n = List.map fst ((cfg#predecessors n)#tolist)
120 let successors cfg n = List.map fst ((cfg#successors n)#tolist)
121 let extract_is_loop cfg n =
122 Control_flow_c.extract_is_loop (cfg#nodes#find n)
123 let print_node i = Format.print_string (string_of_int i)
124 let size cfg = cfg#nodes#length
485bce71 125 let print_graph cfg label border_nodes fill_nodes filename = ()
34e49164
C
126 end
127
128module ENGINE = Ctl_engine.CTL_ENGINE (ENV) (CFG) (PRED)
129
130let test_formula state formula cfg =
131 let label = function
132 Node pred -> [(pred,[],[])]
133 | After ->
134 List.concat
135 (List.map
136 (fun (nodei, node) ->
137 match Control_flow_c.unwrap node with
138 Control_flow_c.AfterNode -> [(nodei,[],[])]
139 | _ -> [])
140 cfg#nodes#tolist) in
141 let verbose = !Flag_ctl.verbose_ctl_engine in
142 let pm = !Flag_ctl.partial_match in
485bce71 143(* let gt = !Flag_ctl.graphical_trace in *)
34e49164
C
144 Flag_ctl.verbose_ctl_engine := false;
145 Flag_ctl.partial_match := false;
485bce71
C
146 Flag_ctl.checking_reachability := true;
147(* Flag_ctl.graphical_trace := ""; *)
34e49164
C
148 let res =
149 ENGINE.sat (cfg,label,List.map fst cfg#nodes#tolist)
150 (CTL.And(CTL.NONSTRICT,CTL.Pred(Node(state)),formula))
151 [[Node(state)]] in
152 Flag_ctl.verbose_ctl_engine := verbose;
153 Flag_ctl.partial_match := pm;
485bce71
C
154 Flag_ctl.checking_reachability := false;
155(* Flag_ctl.graphical_trace := gt; *)
34e49164
C
156 match res with [] -> false | _ -> true
157
158(* ---------------------------------------------------------------- *)
159(* Entry point *)
160
161(* The argument is a list of triples with a node name, an empty environment
162and a witness tree *)
163
164type witness =
165 (Ograph_extended.nodei, unit,
166 (Ograph_extended.nodei, unit, unit) Ast_ctl.generic_ctl list)
167 Ast_ctl.generic_witnesstree
168
169type ('a,'b,'c,'d,'e) triples =
170 (Ograph_extended.nodei * 'a *
171 (Ograph_extended.nodei,
172 ('b, ('c, 'd) Wrapper_ctl.wrapped_binding) CTL.generic_subst list, 'e)
173 CTL.generic_witnesstree list) list
174
175let check_reachability triples cfg =
176 Hashtbl.clear modified;
177 List.iter build_modified triples;
178 let formulas = create_formulas() in
179 List.iter
180 (function (node,af_formula,ef_formula) ->
181 if test_formula node af_formula cfg
182 then
183 if test_formula node ef_formula cfg
184 then
185 Printf.printf "warning: node %d may be inconsistently modified\n"
186 node
187 else ()
188 else
189 failwith
190 (Printf.sprintf
191 "node %d reachable by inconsistent control-flow paths" node))
192 formulas