-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathl_loop.ml
More file actions
178 lines (159 loc) · 6.52 KB
/
Copy pathl_loop.ml
File metadata and controls
178 lines (159 loc) · 6.52 KB
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
(**************************************************************************)
(* *)
(* This file is part of the Frama-C's Lannotate plug-in. *)
(* *)
(* Copyright (C) 2012-2022 *)
(* 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) *)
(* *)
(**************************************************************************)
open Cil_types
open Ast_const
(** Return True if the stmt list only contain 1 statement which is a Break *)
let is_break_only bstmts =
List.length bstmts = 1 &&
match (List.hd bstmts).skind with
| Break _ -> true
| _ -> false
(** Add a label in each loop, to see if we enter in it *)
let inner mk_label = object(_)
inherit Visitor.frama_c_inplace
(** Pile qui stock le status des boucles *)
val inLoopId = Stack.create ()
method! vfunc dec =
if Annotators.shouldInstrumentFun dec.svar then
Cil.DoChildren
else
Cil.SkipChildren
method! vstmt_aux stmt =
match stmt.skind with
| Loop (_,_,l,_,_) ->
let label = mk_label (Exp_builder.one()) [] l in
Cil.DoChildrenPost (fun stmt ->
begin
match stmt.skind with
| Loop (_,b,_,_,_) ->
let found = ref false in
(* Cf. doc/loops.markdown for more info *)
let len = List.length b.bstmts in
let f id s =
match s.skind with
| If (e,th,el,l) ->
(* If not found already && then is empty && else contains only break &&
(isn't the last stmt in the body, or we don't want to handle do..while..) *)
if not !found && th.bstmts = [] && is_break_only el.bstmts && (id+1 <> len || not (Options.HandleDoWhile.get())) then begin
s.skind <- (If (e,{th with bstmts = [label]},el,l));
found := true
end;
s
| _ -> s
in
let nb = List.mapi f b.bstmts in
if !found then
b.bstmts <- nb
else
b.bstmts <- label :: b.bstmts;
stmt
| _ -> assert false
end
)
| _ ->
Cil.DoChildren
end
(** Add a label in each loop, to see if we enter in it *)
let outter mk_label = object(self)
inherit Visitor.frama_c_inplace
(** Pile qui stock le status des boucles *)
val inLoopId = Stack.create ()
method private mk_comp ?(loc=Cil_datatype.Location.unknown) vi value =
let new_exp = Exp_builder.mk ~loc (Lval (Var vi, NoOffset)) in
Exp_builder.binop Eq new_exp value
method private mkSeq loc =
let id_seq = Annotators.getCurrentLabelId () + 1 in (* sequence id *)
let vInfo = Cil.makeVarinfo false false
("__SEQ_STATUS_"^ string_of_int id_seq) Cil.intType
in
let use = self#mk_comp vInfo (Exp_builder.one ()) in
let lbl_use = mk_label use [] loc in
let def =
Local_init(vInfo,AssignInit(SingleInit(Exp_builder.one ())),loc)
|> Stmt_builder.instr
in
let cond =
Ast_info.mkassign (Var vInfo, NoOffset) (Exp_builder.zero ()) loc
|> Stmt_builder.instr
in
def,lbl_use,cond
method! vfunc dec =
if Annotators.shouldInstrumentFun dec.svar then
Cil.DoChildren
else
Cil.SkipChildren
method! vstmt_aux stmt =
match stmt.skind with
| Loop _ ->
let def,use,cond = self#mkSeq (Cil_datatype.Stmt.loc stmt) in
Cil.DoChildrenPost (fun stmt ->
let newLoop =
match stmt.skind with
| Loop (_,b,_,_,_) ->
let found = ref false in
(* Cf. doc/loops.markdown for more info *)
let len = List.length b.bstmts in
let f id s =
match s.skind with
| If (e,th,el,l) ->
(* If not found already && then is empty && else contains only break &&
(isn't the last stmt in the body, or we don't want to handle do..while..) *)
if not !found && th.bstmts = [] && is_break_only el.bstmts
&& (id+1 <> len || not (Options.HandleDoWhile.get ())) then begin
s.skind <- (If (e,{th with bstmts = [cond]},el,l));
found := true
end;
s
| _ -> s
in
let nb = List.mapi f b.bstmts in
if !found then
b.bstmts <- nb
else
b.bstmts <- cond :: b.bstmts;
stmt
| _ -> assert false
in
Stmt_builder.block [def;newLoop;use]
)
| _ ->
Cil.DoChildren
end
let warning () =
if Options.HandleDoWhile.get () then
Options.warning "Handle Do While enabled : Empty loops will be considered as Do..While"
else
Options.warning "Handle Do While disabled : Do..While will be considered as Empty loops";
include Annotators.Register (struct
let name = "ELO"
let help = "Enter in Loop at least once Coverage"
let apply mk_label ast =
warning();
Visitor.visitFramacFileSameGlobals (inner mk_label) ast
end)
include Annotators.Register (struct
let name = "SLO"
let help = "Skip Loop at least Once Coverage"
let apply mk_label ast =
warning();
Visitor.visitFramacFileSameGlobals (outter mk_label) ast
end)