-
Notifications
You must be signed in to change notification settings - Fork 2
/
caret_visitor.ml
1746 lines (1513 loc) · 41.6 KB
/
caret_visitor.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
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
open Cil
open Cil_types
open Cil_datatype
open Rsmast
open Rsm
open Formula_datatype
open Formula_utils
open Caretast
open Atoms
open Atoms_utils
open Type_RState
open Type_Box
open Type_Rsm_module
exception Func_not_found
exception Not_Treated_Prev of (r_module * kernel_function * stmt)
type call = Mod of r_module | Fun of kernel_function
let dkey = Caret_option.register_category "caret_vis:module"
let dkey_vis = dkey
let dkey_trans = Caret_option.register_category "caret_vis:trans"
let hash_printer fmt =
Stmt.Hashtbl.iter
(fun stmt _ ->
Format.fprintf fmt "-> %a\n"
Printer.pp_stmt stmt)
let ignored_functions = ref []
let compute_ignored_functions () =
let fun_str = Caret_option.Ignore_fun.get () in
let str_list = Str.split (Str.regexp ";") fun_str in
ignored_functions :=
List.map (fun func -> Globals.Functions.find_by_name func) str_list
(* varinfo -> mod *)
let func_mod_hashtbl =
Varinfo.Hashtbl.create 9
(* Module -> (Stmt -> RState set) *)
let mod_stmt_states_hashtbl:
(((RState.Set.t) Stmt.Hashtbl.t) Rsm_module.Hashtbl.t) =
Rsm_module.Hashtbl.create 9
(* Call stmt -> Call state list,Return state list *)
let stmt_call_ret_hashtbl = Stmt.Hashtbl.create 14
(* A set containing the unreachable stmts *)
let unreachable_stmts = ref Stmt.Set.empty
(* A list containing the states not treated until the end. It happens sometimes,
frequently when there is if inside if. We need to treat them later. *)
let todo_states = ref []
let todoAdd info =
todo_states := info :: !todo_states
(** Create a list a states from a single statement. For each statement, we
create the new state (stmt, atom, info) for each atom *)
let mkRStateSetFromStmt name stmt kf r_mod atoms =
let test atom =
(*(getAtomKind atom) = at_kind &&*)
(isConsistent stmt kf atom)
in
if isMainMod r_mod
then
Atom.Set.fold
(fun atom acc ->
if test atom
then
let () =
Caret_option.debug ~dkey ~level:1
"Atom %a accepted in stmt %a"
Atom.pretty atom
Printer.pp_stmt stmt
in
RState.Set.add
(mkRState
( name ^ (string_of_int stmt.sid)^"_inf" )
stmt
atom
(Tag Inf)
r_mod
)
acc
else
let () =
Caret_option.debug ~dkey ~level:1
"Atom %a not accepted in stmt %a"
Atom.pretty atom
Printer.pp_stmt stmt
in
acc )
atoms
RState.Set.empty
else
if Caret_option.Only_main.get ()
then
Atom.Set.fold
(fun atom acc ->
if test atom
then
RState.Set.add
(mkRState
( name ^ (string_of_int stmt.sid)^"_fin" )
stmt
atom
(Tag Fin)
r_mod
)
acc
else acc )
atoms
RState.Set.empty
else Atom.Set.fold
(fun atom acc ->
if test atom
then
let inf_state =
(mkRState
( name ^ (string_of_int stmt.sid)^"_inf" )
stmt
atom
(Tag Inf)
r_mod
)
in
RState.Set.add
(mkRState
( name ^ (string_of_int stmt.sid)^"_fin" )
stmt
atom
(Tag Fin)
r_mod
)
(RState.Set.add inf_state acc)
else acc
)
atoms
RState.Set.empty
let updateModStmtHashtbl r_mod stmt s_set =
try
let () =
Caret_option.debug ~dkey:dkey_vis ~level:2
"Registering %a in mod %a"
Printer.pp_stmt stmt
Rsm_module.pretty r_mod
in
Stmt.Hashtbl.add
(Rsm_module.Hashtbl.find mod_stmt_states_hashtbl r_mod)
stmt
s_set;
Caret_option.debug ~dkey:dkey_vis ~level:2
"Registered"
with
Not_found ->
let () =
Caret_option.debug ~dkey:dkey_vis ~level:2
"Registration failed"
in
let mod_list =
Rsm_module.Hashtbl.fold
(fun key_mod _ acc -> acc ^ "--" ^ (key_mod.mod_name))
mod_stmt_states_hashtbl
""
in
Caret_option.debug
~level:3
("Module seeked : %s \nList of modules registered : %s\n")
r_mod.mod_name
mod_list;
Caret_option.fatal
~dkey
("Module not registered.")
let rsm_create_modules rsm formula atoms =
(* We will check which atom can be a return atom, ie if it satisfies
absNextReq for another atom.
If not, we won't have to create the corresponding return state.
*)
object(self)
inherit Visitor.frama_c_inplace
method! vglob_aux g =
match g with
|GFun (fundec,_) ->
let () = Caret_option.debug ~dkey
(*"Treatment of %a@"
Cil_datatype.Varinfo.pretty fundec.svar*)
"Treatment of %s" fundec.svar.vorig_name
in
let kf = Extlib.the self#current_kf in
let vi = Kernel_function.get_vi kf in
if (not (!Db.Value.is_called kf)) || (List.mem kf !ignored_functions)
then
let () = Caret_option.debug ~dkey "%s is ignored"
vi.vorig_name
in
DoChildren
else
let new_mod = mkModule (vi.vname ^ "_rmod") vi in
let () = addMod new_mod rsm in
let () = Varinfo.Hashtbl.add func_mod_hashtbl vi new_mod in
let entry_stmt = Cil.mkEmptyStmt ~valid_sid:true () in
let exit_stmt = Cil.mkEmptyStmt ~valid_sid:true () in
let entry_states =
Atom.Set.fold
(fun atom acc ->
if
(isConsistent (List.hd fundec.sbody.bstmts) kf atom)
then
begin
let new_state_fin =
(mkRState
( "entry" ^new_mod.mod_name^ "_fin" )
entry_stmt
atom
(Tag Fin)
new_mod
)
in
let new_state_inf =
(mkRState
( "entry" ^ new_mod.mod_name ^ "_inf" )
entry_stmt
atom
(Tag Inf)
new_mod
)
in
(*let () = Rsm.addInfRState new_state_inf rsm in*)
if
vi.vorig_name = "main"
then
let () =
if
formInAtom formula atom
&& (Id_Formula.Set.is_empty (callerFormulas atom))
then
let () =
Caret_option.debug
~dkey
~level:2
"%a is a start"
RState.pretty new_state_inf
in setStart new_state_inf rsm
else
Caret_option.debug
~dkey
~level:2
"%a is not a start : %b"
RState.pretty new_state_inf
(formInAtom formula atom)
in
new_state_inf::acc
else
new_state_fin::new_state_inf::acc
end
else acc
)
(Hashtbl.find atoms IInt)
[]
in
let exit_states =
Atom.Set.fold
(fun atom acc ->
if Atoms_utils.hasPositiveAbstractNext atom then acc else
(mkRState
("exit"
^ new_mod.mod_name ^ "_"
^ vi.vname ^ "_rmod")
exit_stmt
atom
TagR
new_mod
)::acc
)
(Hashtbl.find atoms IInt)
[]
in
addEntries entry_states new_mod;
addExits exit_states new_mod;
(* We need to update our tables *)
Rsm_module.Hashtbl.add
mod_stmt_states_hashtbl
new_mod
(Stmt.Hashtbl.create 19);
DoChildren
| _ -> SkipChildren
end
(*
let (state_to_call_hashtbl: Atom.Set.t Atom.Hashtbl.t) =
Atom.Hashtbl.create (Atom.Set.cardinal atoms)
let (state_to_exit_hashtbl: Atom.Set.t Atom.Hashtbl.t) =
Atom.Hashtbl.create (Atom.Set.cardinal atoms)
let (ret_to_state_hashtbl: Atom.Set.t Atom.Hashtbl.t) =
Atom.Hashtbl.create (Atom.Set.cardinal atoms)
(* A -> A' -> (t * t' * bool) list *)
let (state_to_state_hashtbl:
((Rsmast.info * Rsmast.info) Atom.Hashtbl.t) Atom.Hashtbl.t) =
Atom.Hashtbl.create (Atom.Set.cardinal atoms)
*)
let createTransTo closure r_mod kf actual_stmt =
(* We have to create 4 kind of transitions :
- From states to calls
- From states to exits
- From returns to states
- What is left, state to state.
Some of these tests have to be done many times, that's why we will save
our results in the previous hashtbl.*)
let () =
Caret_option.debug
~dkey:dkey_trans
"Computation of transitions for states with statement %a"
Printer.pp_stmt actual_stmt in
let stmt_hshtbl =
try
Rsm_module.Hashtbl.find mod_stmt_states_hashtbl r_mod
with
Not_found ->
Caret_option.fatal
"Module %s not registered properly. Modules registered : %s"
(Rsm_module.varname r_mod)
(Rsm_module.Hashtbl.fold
(fun key _ acc -> acc ^ "\n" ^ key.mod_name)
mod_stmt_states_hashtbl
"\n")
in
let state_set =
try
Stmt.Hashtbl.find stmt_hshtbl actual_stmt
with
Not_found ->
(* The actual statement is not registered in the statement hashtable,
we check the one containing only call statements. *)
try
fst (Stmt.Hashtbl.find stmt_call_ret_hashtbl actual_stmt)
with
Not_found ->
Caret_option.debug ~dkey
"Statement seeked : %a\n Statements registered : \nCALL_RET: %a \n STMTS: %a"
Printer.pp_stmt actual_stmt
hash_printer stmt_call_ret_hashtbl
hash_printer stmt_hshtbl;
Caret_option.fatal ~dkey
"Call/Ret Statement not registered. Don't forget to add the actual statement\
to the hashtable before creating the transitions"
in
let isFirstStmt stmt =
Stmt.equal
(Kernel_function.find_first_stmt kf)
stmt
in
let prev_lists =
if isFirstStmt actual_stmt
then
(* This is the first statement of the function *)
let () = Caret_option.debug
~dkey:dkey_trans
"This is the first statement of the function %s"
(Kernel_function.get_name kf)
in
[r_mod.entries]
else []
in
let prev_lists =
List.fold_left
(fun acc prev_stmt ->
let () =
Caret_option.debug
~dkey:dkey_trans
"Previous statement : %a"
Printer.pp_stmt prev_stmt in
let prev_list =
try
(Stmt.Hashtbl.find stmt_hshtbl prev_stmt)
with
Not_found ->
(* stmt_hshtbl doesn't contain prev_stmt, which means
it should be a Call. For each Call, two kind of
states were generated : calls and returns. If the
previous statement A of a statement B is a Call,
then B states needs a transition from return to
them. *)
let () = Caret_option.debug
~dkey:dkey_trans
"stmt not registered in stmt_hashtbl"
in
let call_prev =
try
let res =
snd
(Stmt.Hashtbl.find
stmt_call_ret_hashtbl
prev_stmt)
in let () =
Caret_option.debug
~dkey:dkey_trans
"But it is in the call_ret hashtbl. Example : %a"
RState.pretty (RState.Set.choose res)
in res
with
Not_found ->
(* Last hope... is the statement reachable ? *)
if (Stmt.Set.mem prev_stmt !unreachable_stmts)
then RState.Set.empty
else
begin
Caret_option.debug ~dkey:dkey_trans
"Statement seeked : %a with id %d \n\
Statements registered : %a\n %a"
Printer.pp_stmt prev_stmt
prev_stmt.sid
hash_printer stmt_hshtbl
hash_printer stmt_call_ret_hashtbl;
raise (Not_Treated_Prev (r_mod, kf ,actual_stmt))
end
in
call_prev
in
let () =
Caret_option.debug
~dkey:dkey_trans "%i states" (RState.Set.cardinal prev_list)
in
prev_list::acc
)
prev_lists
actual_stmt.preds
in
(* If we are looking at the 1st statement of a function, we add the entry
states. *)
(*let prev_lists =
match kf.fundec with
Definition (fundec,_) ->
if (List.hd fundec.sallstmts).sid = actual_stmt.sid
then r_mod.entries :: prev_lists
else prev_lists
| Declaration _ -> assert false
in
*)
(* Fourth case : Node to node. *)
let nodeToNodeTest prev_state state =
Caret_option.debug
~dkey:dkey_trans ~level:2
"Test nodeToNode : \n %a \n to %a ?"
Atom.pretty prev_state.s_atom
Atom.pretty state.s_atom;
let atom_prev = prev_state.s_atom in (* A *)
let info_prev = prev_state.s_info in (* t *)
let atom_state = state.s_atom in (* A' *)
let info_state = state.s_info in (* t' *)
let glNext = glNextReq closure atom_prev atom_state
and absNext = absNextReq closure atom_prev atom_state
and callEq =
Id_Formula.Set.equal
(callerFormulas atom_prev)
(callerFormulas atom_state)
in
Caret_option.debug
~dkey:dkey_trans ~level:3
"%b -- %b -- %b -- %b"
(info_prev = info_state)
glNext
absNext
callEq;
info_prev = info_state && glNext && absNext && callEq
(* First case : state.s_stmt = Instr (Call _ ) *)
in
let transToCallTest prev_state call_state =
Caret_option.debug
~dkey:dkey_trans ~level:2
"Test transToCall";
(* call_state is supposed to be a call, so call_state.box is not
empty. However, if the function is not registered (builtin for example),
it is just a simple state. *)
if call_state.call = None
then
begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"This call state is not the call of a registered function.";
nodeToNodeTest prev_state call_state
end
else
begin
let atom_prev = prev_state.s_atom in (* A *)
let info_prev = prev_state.s_info in (* t *)
let box,_ = Extlib.the call_state.call in
let atom_box = box.box_atom in (* A' *)
let info_box = Tag (box.box_tag) in (* t' *)
(* let atom_entry = call_state.s_atom in (* A'' *) *)
(*let info_entry = entry_state.s_info in (* t'' *)*)
let () =
Caret_option.debug ~dkey:dkey_trans ~level:3
"%b %b %b %b %b"
(info_prev = info_box)
(isConsistent actual_stmt ~after:false kf atom_box)
(glNextReq closure atom_prev atom_box)
(absNextReq closure atom_prev atom_box)
(Id_Formula.Set.equal
(callerFormulas atom_prev)
(callerFormulas atom_box))
in
(info_prev = info_box) &&
(isConsistent actual_stmt ~after:false kf atom_box) &&
(glNextReq closure atom_prev atom_box) &&
(absNextReq closure atom_prev atom_box) &&
(Id_Formula.Set.equal
(callerFormulas atom_prev)
(callerFormulas atom_box))
end
(*
&& glNextReq closure atom_box atom_entry
&& (let temp_list =
List.filter
(fun form -> match form with
CNext(Past,f) ->
List.mem f atom_box
| _ -> false)
closure
in equivList atom_entry temp_list) *)
(* The previous tests are done during the call state creation, as their
validity don't depend on the next state. Check for LBLCALLTEST *)
and transToExitTest return_state exit_state =
(* Second case : state.s_stmt has no successors.
Those statements are not considered as exit statements, we need to
create two trans : from prevs to returns and from returns to exit.
If a return does not satisfies the needed properties, none of these
trans will be created. Also, we consider the transition
prev -> return stmt as a node to node transition (4th case) *)
Caret_option.debug
~dkey:dkey_trans ~level:2
"Test transToExit";
let atom_ret = return_state.s_atom in (* A *)
let info_ret = return_state.s_info in (* t *)
let atom_exit = exit_state.s_atom in (* A' *)
(*let info_exit = match exit_state.s_info with (* R *)
IProp a -> a
| Tag _ ->
Caret_option.fatal
~dkey
"This state is not associated to an exit."
in*)
(*(not(Atoms_utils.hasAbstractNext atom_exit))&& -- Assured by construction,
test already done*)
(info_ret = Tag Fin) &&
(glNextReq closure atom_ret atom_exit) &&
(absNextReq closure atom_ret atom_exit) &&
(Id_Formula.Set.equal
(callerFormulas atom_ret)
(callerFormulas atom_exit))
(*&& let test? = (glNextReq closure atom_exit info_exit) *)
(* Can be tested at creation, check for LBLEXIT*)
(* Third case : ret to states. Ret is here to describe the "after_call"
state, which is not represented by a statement in the source code. *)
and retToNodeTest prev_state state =
Caret_option.debug
~dkey:dkey_trans ~level:2
"Test retToNode";
if prev_state.return = None
then
begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"This return state is not the return of a registered function.";
nodeToNodeTest prev_state state
end
else
let prev_box,_ = Extlib.the prev_state.return in
(* let box_atom = prev_box.box_atom in *) (* A *)
let box_info = prev_box.box_tag in (* t *)
(* let exit_atom = exit_state.s_atom in *) (* A' *)
let exit_info = (* R *)
prev_state.s_atom
in
let state_atom = state.s_atom in (* A'' *)
let state_info = state.s_info in (* t'' *)
(*Caret_option.debug
~dkey:dkey_trans
"%b -- %b -- %b -- %b "
(state_info = Tag box_info)
(glNextReq closure exit_info state_atom)
(absNextReq closure exit_info state_atom)
(Id_Formula.Set.equal
(callerFormulas exit_info)
(callerFormulas state_atom));*)
(state_info = Tag box_info)
(* && absNextReq closure box_atom exit_atom
&& (equivList
(callerFormulas box_atom)
(callerFormulas exit_atom))
&& (isConsistent actual_stmt ret_atom)*)
(* The previous tests are done during the state creation, as their validity
don't depend on the next state. Check for LBLRETTEST. *)
&& glNextReq closure exit_info state_atom
&& absNextReq closure exit_info state_atom
&& (Id_Formula.Set.equal
(callerFormulas exit_info)
(callerFormulas state_atom))
in
let modificationTest pre_state post_state =
let () = Caret_option.debug ~dkey:dkey_trans ~level:2
"Modification test" in
match post_state.s_stmt.skind with
(*Instr (Set ((Var var,_),_,_)) ->
noSideEffectNextReq
~var
pre_state.s_atom
post_state.s_atom true*)
| Instr (Set ((Var var,_),_,_)) ->
let lvar = Cil.cvar_to_lvar var in
let atom_is_affected =
Id_Formula.Set.exists
(fun p ->
match p.form with
CProp (p,_) -> Smt_solver.pred_mem lvar p.ip_content
| _ -> false
)
in (* if both atoms uses the value of var, then the atoms should be no side effect
*)
(atom_is_affected pre_state.s_atom.atom || atom_is_affected post_state.s_atom.atom)
|| (noSideEffectNextReq
pre_state.s_atom
post_state.s_atom)
| Instr (Set _) -> true
| Instr (Call (Some _,_,_,_)) -> true
| Instr (Call (None,{enode = Lval (Var v, _)},_,_)) ->
let func =
Globals.Functions.find_by_name v.vorig_name in
not(List.mem func !ignored_functions) &&
(noSideEffectNextReq
pre_state.s_atom
post_state.s_atom)
(* todo : test if there is really a modification *)
| Instr (Asm _) ->
Caret_option.debug
~dkey:dkey_trans
~level:2
"ASM not supported"; true
| Instr _
| Goto _
| Break _
| Continue _
| If _
| Switch _
| Loop _
| Block _
| Return _
| Throw _ | TryCatch _ | TryFinally _ | TryExcept _ ->
(* In this case, there is no modification
of any variable : we check if the atomic
properties are the same *)
noSideEffectNextReq
pre_state.s_atom
post_state.s_atom
| UnspecifiedSequence _ -> true
in
let treatRStates goodTest start_set next_set =
if RState.Set.is_empty start_set || RState.Set.is_empty next_set then () else
let () =
Caret_option.debug
~dkey:dkey_trans
"link %i states\nto %a:%i states"
(RState.Set.cardinal start_set)
Printer.pp_stmt (RState.Set.choose next_set).s_stmt
(RState.Set.cardinal next_set)
in
RState.Set.iter
(fun start_state ->
let () =
Caret_option.debug
~dkey:dkey_trans
~level:1
"%a : test with %i states"
RState.pretty start_state
(RState.Set.cardinal next_set)
in
RState.Set.iter
(fun next_state ->
Caret_option.debug
~dkey:dkey_trans ~level:2
"Test of :\n%a\nWith atom :\n %a\n-> %a\n with atom n%a :"
RState.pretty start_state
Atom.pretty start_state.s_atom
RState.pretty next_state
Atom.pretty next_state.s_atom;
if
(not (modificationTest start_state next_state))
then
Caret_option.debug
~dkey:dkey_trans ~level:2
"Fail as there is no modification but the atomic properties are differents"
else
if (goodTest start_state next_state)
then begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"Success";
(Rsm.mkTrans start_state next_state) end
else
Caret_option.debug
~dkey:dkey_trans ~level:2
"Fail"
)
next_set
)
start_set;
Caret_option.debug ~dkey:dkey_trans ~level:2
"Linking done"
in
let treatCall prev_is_ret prev_states =
let goodTest =
if prev_is_ret
then (fun prev cur ->
(*Caret_option.debug
~dkey:dkey_trans
"retToNodeTest & transToCall done";*)
(retToNodeTest prev cur) && (transToCallTest prev cur))
else
begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"transToCall done : prev_state size = %d, actual = %d"
(RState.Set.cardinal prev_states)
(RState.Set.cardinal state_set);
transToCallTest
end
in
treatRStates goodTest prev_states state_set
in
let treatNormal prev_is_ret prev_states =
let goodTest =
if prev_is_ret
then
begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"retToNode done";
retToNodeTest
end
else
begin
Caret_option.debug
~dkey:dkey_trans ~level:2
"ToNode done";
nodeToNodeTest
end
in
treatRStates goodTest prev_states state_set
in
let treatRet prev_is_ret prev_states =
Caret_option.debug ~level:2
~dkey:dkey_trans
"In treatToRet : ";
let () = treatNormal prev_is_ret prev_states in
let goodTest = transToExitTest
(*
if prev_is_ret
then (fun cur ext ->
(retToNodeTest prev cur) && (transToExitTest cur ext))
else (fun prev cur ext ->
(nodeToNodeTest prev cur) && (transToExitTest cur ext))*)
in
let exit_states = r_mod.exits in
(treatRStates goodTest state_set exit_states)
in
Caret_option.debug
~dkey:dkey_trans ~level:2
"Computing transitions for statement %a"
Printer.pp_stmt actual_stmt;
let () =
List.iter
(fun prev_states ->
(* Tests if the previous states are states returning from a call.
If so, retToNodeTest must be done. *)
Caret_option.debug
~level:3
~dkey:dkey_trans
"Computing from the %i previous states"
(RState.Set.cardinal prev_states);
let prev_is_ret =
try
isRet (RState.Set.choose prev_states)
with
Not_found -> false (* false because, well, there's nothing *)
in
if actual_stmt.succs = []
(* The end of a function is always a return in Cil*)
then
begin
Caret_option.debug
~dkey:dkey_trans
"Statement %a is the end of a function"
Printer.pp_stmt actual_stmt;
treatRet prev_is_ret prev_states
end
else
begin
Caret_option.debug
~dkey:dkey_trans
"Statement %a is not the end of a function"
Printer.pp_stmt actual_stmt;
Caret_option.debug
~dkey:dkey_trans
"Succs :\n%a"
(Format.pp_print_list Printer.pp_stmt) actual_stmt.succs;
match actual_stmt.skind with
Instr ( Cil_types.Call _ ) ->
Caret_option.debug
~dkey:dkey_trans
"Statement %a is a Call"
Printer.pp_stmt actual_stmt;
treatCall prev_is_ret prev_states
| Return _ ->
Caret_option.debug
~dkey:dkey_trans
"Statement %a is a Return"
Printer.pp_stmt actual_stmt;
treatRet prev_is_ret prev_states
| _ ->
Caret_option.debug
~dkey:dkey_trans
"Statement %a is not a Call nor a Return"
Printer.pp_stmt actual_stmt;
treatNormal prev_is_ret prev_states
end
)
prev_lists;
Caret_option.debug ~dkey:dkey_trans ~level:2 "Statement treatment done";
in ()
let rsm_create_states closure atoms =
object(self)
inherit Visitor.frama_c_inplace
method! vstmt_aux stmt =
let () =
Caret_option.debug ~dkey:dkey_vis
"Statement treated : %a with id %d"
Printer.pp_stmt stmt
stmt.sid
in
let kf = Extlib.the self#current_kf in
if List.mem kf !ignored_functions
then SkipChildren
else
let vi = Kernel_function.get_vi kf in
(*
if (Cil.is_builtin vi) (* || not(Db.Value.is_reachable state)*)
then
let () =
Caret_option.debug ~dkey:dkey_vis ~level:2
"The studied function is a builtin, we don't treat it yet."
in
SkipChildren
else
*)
let state = Db.Value.get_stmt_state stmt in
if Caret_option.Unreachable_states.get () && not(Db.Value.is_reachable state)
then
let isret = function | Return _ -> true | _ -> false in
let () =
if
(Caret_option.Main_ends.get ())