3
* Copyright (C) 2006, 2007 Ecole des Mines de Nantes
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License (GPL)
7
* version 2 as published by the Free Software Foundation.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* file license.txt for more details.
24
(*****************************************************************************)
25
(* todo?: compute target level with goto (but rare that different I think)
27
* ver2: compute depth of label (easy, intercept compound in the visitor)
29
* checktodo: after a switch, need check that all the st in the
30
* compound start with a case: ?
32
* checktodo: how ensure that when we call aux_statement recursivly, we
33
* pass it xi_lbl and not just auxinfo ? how enforce that ?
34
* in fact we must either pass a xi_lbl or a newxi
36
* todo: can have code (and so nodes) in many places, in the size of an
37
* array, in the init of initializer, but also in StatementExpr, ...
39
* todo?: steal code from CIL ? (but seems complicated ... again) *)
40
(*****************************************************************************)
42
(*****************************************************************************)
44
(*****************************************************************************)
47
| DeadCode of Common.parse_info option
48
| CaseNoSwitch of Common.parse_info
49
| OnlyBreakInSwitch of Common.parse_info
50
| NoEnclosingLoop of Common.parse_info
51
| GotoCantFindLabel of string * Common.parse_info
52
| NoExit of Common.parse_info
53
| DuplicatedLabel of string
56
| Define of Common.parse_info
58
exception Error of error
60
(*****************************************************************************)
62
(*****************************************************************************)
64
let add_node node labels nodestr g =
65
g#add_node (Control_flow_c.mk_node node labels [] nodestr)
66
let add_bc_node node labels parent_labels nodestr g =
67
g#add_node (Control_flow_c.mk_node node labels parent_labels nodestr)
68
let add_arc_opt (starti, nodei) g =
69
starti +> do_option (fun starti -> g#add_arc ((starti, nodei), Direct))
74
let pinfo_of_ii ii = Ast_c.get_opi (List.hd ii).Ast_c.pinfo
78
(*****************************************************************************)
79
(* Contextual information passed in aux_statement *)
80
(*****************************************************************************)
82
(* Sometimes have a continue/break and we must know where we must jump.
84
* ctl_brace: The node list in context_info record the number of '}' at the
85
* context point, for instance at the switch point. So that when deeper,
86
* we can compute the difference between the number of '}' from root to
87
* the context point to close the good number of '}' . For instance
88
* where there is a 'continue', we must close only until the for.
92
| LoopInfo of nodei * nodei (* start, end *) * node list * int list
93
| SwitchInfo of nodei * nodei (* start, end *) * node list * int list
95
(* for the Compound case I need to do different things depending if
96
* the compound is the compound of the function definition, the compound of
97
* a switch, so this type allows to specify this and enable to factorize
98
* code for the Compound
100
and compound_caller =
101
FunctionDef | Statement | Switch of (nodei -> xinfo -> xinfo)
103
(* other information used internally in ast_to_flow and passed recursively *)
106
ctx: context_info; (* cf above *)
107
ctx_stack: context_info list;
109
(* are we under a ifthen[noelse]. Used for ErrorExit *)
111
compound_caller: compound_caller;
113
(* does not change recursively. Some kind of globals. *)
114
labels_assoc: (string, nodei) oassoc;
116
errorexiti: nodei option;
118
(* ctl_braces: the nodei list is to handle current imbrication depth.
119
* It contains the must-close '}'.
120
* update: now it is instead a node list.
132
under_ifthen = false;
133
compound_caller = Statement;
137
(* don't change when recurse *)
138
labels_assoc = new oassocb [];
144
(*****************************************************************************)
145
(* (Semi) Globals, Julia's style. *)
146
(*****************************************************************************)
148
let g = ref (new ograph_mutable)
150
let counter_for_labels = ref 0
151
let counter_for_braces = ref 0
153
(* For switch we use compteur too (or pass int ref) cos need know order of the
154
* case if then later want to go from CFG to (original) AST.
155
* update: obsolete now I think
157
let counter_for_switch = ref 0
160
(*****************************************************************************)
162
(*****************************************************************************)
164
(* alt: do via a todo list, so can do all in one pass (but more complex)
165
* todo: can also count the depth level and associate it to the node, for
168
let compute_labels_and_create_them st =
170
(* map C label to index number in graph *)
171
let (h: (string, nodei) oassoc ref) = ref (new oassocb []) in
174
st +> Visitor_c.vk_statement { Visitor_c.default_visitor_c with
175
Visitor_c.kstatement = (fun (k, bigf) st ->
177
| Labeled (Ast_c.Label (s, _st)),ii ->
178
(* at this point I put a lbl_0, but later I will put the
180
let newi = !g +> add_node (Label (st,(s,ii))) lbl_0 (s^":") in
182
(* the C label already exists ? *)
183
if (!h#haskey s) then raise (Error (DuplicatedLabel s));
184
h := !h#add (s, newi);
185
(* not k _st !!! otherwise in lbl1: lbl2: i++; we miss lbl2 *)
196
let insert_all_braces xs starti =
197
xs +> List.fold_left (fun acc node ->
198
(* Have to build a new node (clone), cos cant share it.
199
* update: This is now done by the caller. The clones are in xs.
201
let newi = !g#add_node node in
202
!g#add_arc ((acc, newi), Direct);
206
(*****************************************************************************)
208
(*****************************************************************************)
210
(* Take in a (optional) start node, return an (optional) end node.
214
* ver1: old code was returning an nodei, but goto has no end, so
215
* aux_statement should return nodei option.
217
* ver2: old code was taking a nodei, but should also take nodei
220
* ver3: deadCode detection. What is dead code ? When there is no
221
* starti to start from ? So make starti an option too ? Si on arrive
222
* sur un label: au moment d'un deadCode, on peut verifier les
223
* predecesseurs de ce label, auquel cas si y'en a, ca veut dire
224
* qu'en fait c'est pas du deadCode et que donc on peut se permettre
225
* de partir d'un starti à None. Mais si on a xx; goto far:; near:
226
* yy; zz; far: goto near:. Bon ca doit etre un cas tres tres rare,
227
* mais a cause de notre parcours, on va rejeter ce programme car au
228
* moment d'arriver sur near: on n'a pas encore de predecesseurs pour
229
* ce label. De meme, meme le cas simple ou la derniere instruction
230
* c'est un return, alors ca va generer un DeadCode :(
232
* So make a first pass where dont launch exn at all. Create nodes,
233
* if starti is None then dont add arc. Then make a second pass that
234
* just checks that all nodes (except enter) have predecessors.
235
* So make starti an option too. So type is now
237
* nodei option -> statement -> nodei option.
239
* todo?: if the pb is at a fake node, then try first successos that
242
* ver4: because of special needs of coccinelle, need pass more info, cf
243
* type additionnal_info defined above.
245
* - to complete (break, continue (and enclosing loop), switch (and
246
* associated case, casedefault)) we need to pass additionnal info.
247
* The start/exit when enter in a loop, to know the current 'for'.
249
* - to handle the braces, need again pass additionnal info.
251
* - need pass the labels.
253
* convention: xi for the auxinfo passed recursively
257
let rec (aux_statement: (nodei option * xinfo) -> statement -> nodei option) =
258
fun (starti, xi) stmt ->
260
if not !Flag_parsing_c.label_strategy_2
261
then incr counter_for_labels;
264
if !Flag_parsing_c.label_strategy_2
266
else xi.labels @ [!counter_for_labels]
269
(* Normally the new auxinfo to pass recursively to the next aux_statement.
270
* But in some cases we add additionnal stuff in which case we don't use
271
* this 'xi_lbl' but a 'newxi' specially built.
274
if !Flag_parsing_c.label_strategy_2
276
compound_caller = Statement;
279
labels = xi.labels @ [ !counter_for_labels ];
280
compound_caller = Statement;
284
(* ------------------------- *)
287
(* coupling: the Switch case copy paste parts of the Compound case *)
288
| Ast_c.Compound statxs, ii ->
290
let (i1, i2) = tuple_of_list2 ii in
293
incr counter_for_braces;
294
let brace = !counter_for_braces in
296
let s1 = "{" ^ i_to_s brace in
297
let s2 = "}" ^ i_to_s brace in
299
let lbl = match xi.compound_caller with
300
| FunctionDef -> xi.labels (* share label with function header *)
301
| Statement -> xi.labels @ [!counter_for_labels]
302
| Switch _ -> xi.labels
305
let newi = !g +> add_node (SeqStart (stmt, brace, i1)) lbl s1 in
306
let endnode = mk_node (SeqEnd (brace, i2)) lbl [] s2 in
307
let endnode_dup = mk_fake_node (SeqEnd (brace, i2)) lbl [] s2 in
310
mk_node (SeqEnd (brace, Ast_c.fakeInfo())) lbl [] s2 in
313
let newxi = { xi_lbl with braces = endnode_dup:: xi_lbl.braces } in
315
let newxi = match xi.compound_caller with
316
| Switch todo_in_compound ->
317
(* note that side effect in todo_in_compound *)
318
todo_in_compound newi newxi
319
| FunctionDef | Statement -> newxi
322
!g +> add_arc_opt (starti, newi);
323
let starti = Some newi in
325
aux_statement_list starti (xi, newxi) statxs
328
+> Common.fmap (fun starti ->
329
(* subtil: not always return a Some.
330
* Note that if starti is None, alors forcement ca veut dire
331
* qu'il y'a eu un return (ou goto), et donc forcement les
332
* braces auront au moins ete crée une fois, et donc flow_to_ast
334
* Sauf si le goto revient en arriere ? mais dans ce cas
335
* ca veut dire que le programme boucle. Pour qu'il boucle pas
336
* il faut forcement au moins un return.
338
let endi = !g#add_node endnode in
339
!g#add_arc ((starti, endi), Direct);
344
(* ------------------------- *)
345
| Labeled (Ast_c.Label (s, st)), ii ->
346
let ilabel = xi.labels_assoc#find s in
347
let node = mk_node (unwrap (!g#nodes#find ilabel)) lbl [] (s ^ ":") in
348
!g#replace_node (ilabel, node);
349
!g +> add_arc_opt (starti, ilabel);
350
aux_statement (Some ilabel, xi_lbl) st
353
| Jump (Ast_c.Goto s), ii ->
354
(* special_cfg_ast: *)
355
let newi = !g +> add_node (Goto (stmt, (s,ii))) lbl ("goto " ^ s ^ ":") in
356
!g +> add_arc_opt (starti, newi);
359
try xi.labels_assoc#find s
361
(* jump vers ErrorExit a la place ?
362
* pourquoi tant de "cant jump" ? pas detecté par gcc ?
364
raise (Error (GotoCantFindLabel (s, pinfo_of_ii ii)))
366
(* !g +> add_arc_opt (starti, ilabel);
367
* todo: special_case: suppose that always goto to toplevel of function,
368
* hence the Common.init
369
* todo?: can perhaps report when a goto is not a classic error_goto ?
370
* that is when it does not jump to the toplevel of the function.
372
let newi = insert_all_braces (Common.list_init xi.braces) newi in
373
!g#add_arc ((newi, ilabel), Direct);
376
| Jump (Ast_c.GotoComputed e), ii ->
377
raise (Error (ComputedGoto))
379
(* ------------------------- *)
380
| Ast_c.ExprStatement opte, ii ->
381
(* flow_to_ast: old: when opte = None, then do not add in CFG. *)
386
let ((unwrap_e, typ), ii) = e in
388
| FunCall (((Ident (namef), _typ), _ii), _args) ->
389
Ast_c.str_of_name namef ^ "(...)"
390
| Assignment (((Ident (namevar), _typ), _ii), SimpleAssign, e) ->
391
Ast_c.str_of_name namevar ^ " = ... ;"
393
(((RecordAccess (((Ident (namevar), _typ), _ii), field), _typ2),
397
let sfield = Ast_c.str_of_name field in
398
Ast_c.str_of_name namevar ^ "." ^ sfield ^ " = ... ;"
403
let newi = !g +> add_node (ExprStatement (stmt, (opte, ii))) lbl s in
404
!g +> add_arc_opt (starti, newi);
408
(* ------------------------- *)
409
| Selection (Ast_c.If (e, st1, (Ast_c.ExprStatement (None), []))), ii ->
410
(* sometome can have ExprStatement None but it is a if-then-else,
411
* because something like if() xx else ;
412
* so must force to have [] in the ii associated with ExprStatement
415
let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in
416
let ii = [i1;i2;i3] in
417
(* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti
419
* |-> newfakeelse -> ... -> finalelse -|
420
* update: there is now also a link directly to lasti.
422
* because of CTL, now do different things if we are in a ifthen or
425
let newi = !g +> add_node (IfHeader (stmt, (e, ii))) lbl ("if") in
426
!g +> add_arc_opt (starti, newi);
427
let newfakethen = !g +> add_node TrueNode lbl "[then]" in
428
let newfakeelse = !g +> add_node FallThroughNode lbl "[fallthrough]" in
429
let afteri = !g +> add_node AfterNode lbl "[after]" in
430
let lasti = !g +> add_node (EndStatement (Some iifakeend)) lbl "[endif]"
433
(* for ErrorExit heuristic *)
434
let newxi = { xi_lbl with under_ifthen = true; } in
436
!g#add_arc ((newi, newfakethen), Direct);
437
!g#add_arc ((newi, newfakeelse), Direct);
438
!g#add_arc ((newi, afteri), Direct);
439
!g#add_arc ((afteri, lasti), Direct);
440
!g#add_arc ((newfakeelse, lasti), Direct);
442
let finalthen = aux_statement (Some newfakethen, newxi) st1 in
443
!g +> add_arc_opt (finalthen, lasti);
447
| Selection (Ast_c.If (e, st1, st2)), ii ->
448
(* starti -> newi ---> newfakethen -> ... -> finalthen --> lasti
450
* |-> newfakeelse -> ... -> finalelse -|
451
* update: there is now also a link directly to lasti.
453
let (iiheader, iielse, iifakeend) =
455
| [i1;i2;i3;i4;i5] -> [i1;i2;i3], i4, i5
456
| _ -> raise Impossible
458
let newi = !g +> add_node (IfHeader (stmt, (e, iiheader))) lbl "if" in
459
!g +> add_arc_opt (starti, newi);
460
let newfakethen = !g +> add_node TrueNode lbl "[then]" in
461
let newfakeelse = !g +> add_node FalseNode lbl "[else]" in
462
let elsenode = !g +> add_node (Else iielse) lbl "else" in
465
!g#add_arc ((newi, newfakethen), Direct);
466
!g#add_arc ((newi, newfakeelse), Direct);
468
!g#add_arc ((newfakeelse, elsenode), Direct);
470
let finalthen = aux_statement (Some newfakethen, xi_lbl) st1 in
471
let finalelse = aux_statement (Some elsenode, xi_lbl) st2 in
473
(match finalthen, finalelse with
474
| (None, None) -> None
477
!g +> add_node (EndStatement(Some iifakeend)) lbl "[endif]" in
479
!g +> add_node AfterNode lbl "[after]" in
480
!g#add_arc ((newi, afteri), Direct);
481
!g#add_arc ((afteri, lasti), Direct);
483
!g +> add_arc_opt (finalthen, lasti);
484
!g +> add_arc_opt (finalelse, lasti);
489
(* ------------------------- *)
490
| Selection (Ast_c.Switch (e, st)), ii ->
491
let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in
492
let ii = [i1;i2;i3] in
494
(* The newswitchi is for the labels to know where to attach.
495
* The newendswitch (endi) is for the 'break'. *)
497
!g+> add_node (SwitchHeader(stmt,(e,ii))) lbl "switch" in
499
!g +> add_node (EndStatement (Some iifakeend)) lbl "[endswitch]" in
501
!g +> add_arc_opt (starti, newswitchi);
503
(* call compound case. Need special info to pass to compound case
504
* because we need to build a context_info that need some of the
505
* information build inside the compound case: the nodei of {
509
| Ast_c.Compound statxs, ii ->
510
let statxs = Ast_c.stmt_elems_of_sequencable statxs in
512
(* todo? we should not allow to match a stmt that corresponds
513
* to a compound of a switch, so really SeqStart (stmt, ...)
514
* here ? so maybe should change the SeqStart labeling too.
515
* So need pass a todo_in_compound2 function.
517
let todo_in_compound newi newxi =
518
let newxi' = { newxi with
519
ctx = SwitchInfo (newi(*!!*), newendswitch, xi.braces, lbl);
520
ctx_stack = newxi.ctx::newxi.ctx_stack
523
!g#add_arc ((newswitchi, newi), Direct);
524
(* new: if have not a default case, then must add an edge
525
* between start to end.
526
* todo? except if the case[range] coverthe whole spectrum
528
if not (statxs +> List.exists (function
529
| (Labeled (Ast_c.Default _), _) -> true
533
(* when there is no default, then a valid path is
534
* from the switchheader to the end. In between we
538
let newafter = !g+>add_node FallThroughNode lbl "[switchfall]"
540
!g#add_arc ((newafter, newendswitch), Direct);
541
!g#add_arc ((newswitchi, newafter), Direct);
543
!g#add_arc ((newswitchi, newendswitch), Direct) +> adjust_g;
548
let newxi = { xi with compound_caller =
549
Switch todo_in_compound
552
aux_statement (None (* no starti *), newxi) st
553
| x -> raise Impossible
555
!g +> add_arc_opt (finalthen, newendswitch);
558
(* what if has only returns inside. We must try to see if the
559
* newendswitch has been used via a 'break;' or because no
563
(match finalthen with
566
let afteri = !g +> add_node AfterNode lbl "[after]" in
567
!g#add_arc ((newswitchi, afteri), Direct);
568
!g#add_arc ((afteri, newendswitch), Direct);
571
!g#add_arc ((finalthen, newendswitch), Direct);
574
if (!g#predecessors newendswitch)#null
576
assert ((!g#successors newendswitch)#null);
577
!g#del_node newendswitch;
582
let afteri = !g +> add_node AfterNode lbl "[after]" in
583
!g#add_arc ((newswitchi, afteri), Direct);
584
!g#add_arc ((afteri, newendswitch), Direct);
594
| Labeled (Ast_c.Case (_, _)), ii
595
| Labeled (Ast_c.CaseRange (_, _, _)), ii ->
597
incr counter_for_switch;
598
let switchrank = !counter_for_switch in
601
| Labeled (Ast_c.Case (e, st)), ii ->
602
(Case (stmt, (e, ii))), st
603
| Labeled (Ast_c.CaseRange (e, e2, st)), ii ->
604
(CaseRange (stmt, ((e, e2), ii))), st
605
| _ -> raise Impossible
608
let newi = !g +> add_node node lbl "case:" in
610
(match Common.optionise (fun () ->
612
(xi.ctx::xi.ctx_stack) +> Common.find_some (function
613
| SwitchInfo (a, b, c, _) -> Some (a, b, c)
617
| Some (startbrace, switchendi, _braces) ->
618
(* no need to attach to previous for the first case, cos would be
620
starti +> do_option (fun starti ->
621
if starti <> startbrace
622
then !g +> add_arc_opt (Some starti, newi);
625
let s = ("[casenode] " ^ i_to_s switchrank) in
626
let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in
627
!g#add_arc ((startbrace, newcasenodei), Direct);
628
!g#add_arc ((newcasenodei, newi), Direct);
629
| None -> raise (Error (CaseNoSwitch (pinfo_of_ii ii)))
631
aux_statement (Some newi, xi_lbl) st
634
| Labeled (Ast_c.Default st), ii ->
635
incr counter_for_switch;
636
let switchrank = !counter_for_switch in
638
let newi = !g +> add_node (Default(stmt, ((),ii))) lbl "case default:" in
639
!g +> add_arc_opt (starti, newi);
642
| SwitchInfo (startbrace, switchendi, _braces, _parent_lbl) ->
643
let s = ("[casenode] " ^ i_to_s switchrank) in
644
let newcasenodei = !g +> add_node (CaseNode switchrank) lbl s in
645
!g#add_arc ((startbrace, newcasenodei), Direct);
646
!g#add_arc ((newcasenodei, newi), Direct);
647
| _ -> raise (Error (CaseNoSwitch (pinfo_of_ii ii)))
649
aux_statement (Some newi, xi_lbl) st
656
(* ------------------------- *)
657
| Iteration (Ast_c.While (e, st)), ii ->
658
(* starti -> newi ---> newfakethen -> ... -> finalthen -
659
* |---|-----------------------------------|
663
let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in
664
let ii = [i1;i2;i3] in
666
let newi = !g +> add_node (WhileHeader (stmt, (e,ii))) lbl "while" in
667
!g +> add_arc_opt (starti, newi);
668
let newfakethen = !g +> add_node InLoopNode lbl "[whiletrue]" in
669
(* let newfakeelse = !g +> add_node FalseNode lbl "[endwhile]" in *)
670
let newafter = !g +> add_node FallThroughNode lbl "[whilefall]" in
672
!g +> add_node (EndStatement (Some iifakeend)) lbl "[endwhile]" in
674
let newxi = { xi_lbl with
675
ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl);
676
ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack
680
!g#add_arc ((newi, newfakethen), Direct);
681
!g#add_arc ((newafter, newfakeelse), Direct);
682
!g#add_arc ((newi, newafter), Direct);
683
let finalthen = aux_statement (Some newfakethen, newxi) st in
684
!g +> add_arc_opt (finalthen, newi);
688
(* This time, may return None, for instance if goto in body of dowhile
689
* (whereas While cant return None). But if return None, certainly
692
| Iteration (Ast_c.DoWhile (st, e)), ii ->
693
(* starti -> doi ---> ... ---> finalthen (opt) ---> whiletaili
694
* |--------- newfakethen ---------------| |---> newfakelse
697
match Ast_c.unwrap_expr e with
698
| Constant (Int "0") -> true
702
let (iido, iiwhiletail, iifakeend) =
704
| [i1;i2;i3;i4;i5;i6] -> i1, [i2;i3;i4;i5], i6
705
| _ -> raise Impossible
707
let doi = !g +> add_node (DoHeader (stmt, iido)) lbl "do" in
708
!g +> add_arc_opt (starti, doi);
709
let taili = !g +> add_node (DoWhileTail (e, iiwhiletail)) lbl "whiletail"
713
(*let newfakeelse = !g +> add_node FalseNode lbl "[enddowhile]" in *)
714
let newafter = !g +> add_node FallThroughNode lbl "[dowhilefall]" in
716
!g +> add_node (EndStatement (Some iifakeend)) lbl "[enddowhile]" in
718
let newxi = { xi_lbl with
719
ctx = LoopInfo (taili, newfakeelse, xi_lbl.braces, lbl);
720
ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack
726
let newfakethen = !g +> add_node InLoopNode lbl "[dowhiletrue]" in
727
!g#add_arc ((taili, newfakethen), Direct);
728
!g#add_arc ((newfakethen, doi), Direct);
731
!g#add_arc ((newafter, newfakeelse), Direct);
732
!g#add_arc ((taili, newafter), Direct);
735
let finalthen = aux_statement (Some doi, newxi) st in
736
(match finalthen with
738
if (!g#predecessors taili)#null
739
then raise (Error (DeadCode (Some (pinfo_of_ii ii))))
740
else Some newfakeelse
742
!g#add_arc ((finali, taili), Direct);
748
| Iteration (Ast_c.For (e1opt, e2opt, e3opt, st)), ii ->
749
let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in
750
let ii = [i1;i2;i3] in
753
!g+>add_node(ForHeader(stmt,((e1opt,e2opt,e3opt),ii))) lbl "for" in
754
!g +> add_arc_opt (starti, newi);
755
let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in
756
(*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*)
757
let newafter = !g +> add_node FallThroughNode lbl "[forfall]" in
759
!g +> add_node (EndStatement (Some iifakeend)) lbl "[endfor]" in
761
let newxi = { xi_lbl with
762
ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl);
763
ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack
767
!g#add_arc ((newi, newfakethen), Direct);
768
!g#add_arc ((newafter, newfakeelse), Direct);
769
!g#add_arc ((newi, newafter), Direct);
770
let finalthen = aux_statement (Some newfakethen, newxi) st in
771
!g +> add_arc_opt (finalthen, newi);
775
(* to generate less exception with the breakInsideLoop, analyse
776
* correctly the loop deguisé comme list_for_each. Add a case ForMacro
777
* in ast_c (and in lexer/parser), and then do code that imitates the
779
* update: the list_for_each was previously converted into Tif by the
780
* lexer, now they are returned as Twhile so less pbs. But not perfect.
781
* update: now I recognize the list_for_each macro so no more problems.
783
| Iteration (Ast_c.MacroIteration (s, es, st)), ii ->
784
let (i1,i2,i3, iifakeend) = tuple_of_list4 ii in
785
let ii = [i1;i2;i3] in
788
!g+>add_node(MacroIterHeader(stmt,((s,es),ii))) lbl "foreach" in
789
!g +> add_arc_opt (starti, newi);
790
let newfakethen = !g +> add_node InLoopNode lbl "[fortrue]" in
791
(*let newfakeelse = !g +> add_node FalseNode lbl "[endfor]" in*)
792
let newafter = !g +> add_node FallThroughNode lbl "[foreachfall]" in
794
!g +> add_node (EndStatement (Some iifakeend)) lbl "[endforeach]" in
796
let newxi = { xi_lbl with
797
ctx = LoopInfo (newi, newfakeelse, xi_lbl.braces, lbl);
798
ctx_stack = xi_lbl.ctx::xi_lbl.ctx_stack
802
!g#add_arc ((newi, newfakethen), Direct);
803
!g#add_arc ((newafter, newfakeelse), Direct);
804
!g#add_arc ((newi, newafter), Direct);
805
let finalthen = aux_statement (Some newfakethen, newxi) st in
806
!g +> add_arc_opt (finalthen, newi);
811
(* ------------------------- *)
812
| Jump ((Ast_c.Continue|Ast_c.Break) as x),ii ->
815
SwitchInfo (startbrace, loopendi, braces, parent_lbl) ->
820
xi.ctx_stack +> Common.find_some (function
821
LoopInfo (_,_,_,_) as c -> Some c
824
raise (Error (OnlyBreakInSwitch (pinfo_of_ii ii))))
825
| LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> xi.ctx
826
| NoInfo -> raise (Error (NoEnclosingLoop (pinfo_of_ii ii))) in
829
match context_info with
830
LoopInfo (loopstarti, loopendi, braces, parent_lbl) -> parent_lbl
831
| SwitchInfo (startbrace, loopendi, braces, parent_lbl) -> parent_lbl
832
| NoInfo -> raise Impossible in
835
let (node_info, string) =
837
String.concat "," (List.map string_of_int parent_label) in
840
(Continue (stmt, ((), ii)),
841
Printf.sprintf "continue; [%s]" parent_string)
843
(Break (stmt, ((), ii)),
844
Printf.sprintf "break; [%s]" parent_string)
845
| _ -> raise Impossible
848
(* idea: break or continue records the label of its parent loop or
850
let newi = !g +> add_bc_node node_info lbl parent_label string in
851
!g +> add_arc_opt (starti, newi);
853
(* let newi = some starti in *)
855
(match context_info with
856
| LoopInfo (loopstarti, loopendi, braces, parent_lbl) ->
859
| Ast_c.Break -> loopendi
860
| Ast_c.Continue -> loopstarti
861
| x -> raise Impossible
863
let difference = List.length xi.braces - List.length braces in
864
assert (difference >= 0);
865
let toend = take difference xi.braces in
866
let newi = insert_all_braces toend newi in
867
!g#add_arc ((newi, desti), Direct);
870
| SwitchInfo (startbrace, loopendi, braces, parent_lbl) ->
871
assert (x =*= Ast_c.Break);
872
let difference = List.length xi.braces - List.length braces in
873
assert (difference >= 0);
874
let toend = take difference xi.braces in
875
let newi = insert_all_braces toend newi in
876
!g#add_arc ((newi, loopendi), Direct);
878
| NoInfo -> raise Impossible
881
| Jump ((Ast_c.Return | Ast_c.ReturnExpr _) as kind), ii ->
882
(match xi.exiti, xi.errorexiti with
883
| None, None -> raise (Error (NoExit (pinfo_of_ii ii)))
884
| Some exiti, Some errorexiti ->
889
| Ast_c.Return -> "return"
890
| Ast_c.ReturnExpr _ -> "return ..."
891
| _ -> raise Impossible
896
| Ast_c.Return -> Return (stmt, ((),ii))
897
| Ast_c.ReturnExpr e -> ReturnExpr (stmt, (e, ii))
898
| _ -> raise Impossible
902
!g +> add_arc_opt (starti, newi);
903
let newi = insert_all_braces xi.braces newi in
906
then !g#add_arc ((newi, errorexiti), Direct)
907
else !g#add_arc ((newi, exiti), Direct)
910
| _ -> raise Impossible
914
(* ------------------------- *)
915
| Ast_c.Decl decl, ii ->
919
([{v_namei = Some (name, _); v_type = typ; v_storage = sto}, _], _)) ->
920
"decl:" ^ Ast_c.str_of_name name
921
| _ -> "decl_novar_or_multivar"
924
let newi = !g +> add_node (Decl (decl)) lbl s in
925
!g +> add_arc_opt (starti, newi);
928
(* ------------------------- *)
929
| Ast_c.Asm body, ii ->
930
let newi = !g +> add_node (Asm (stmt, ((body,ii)))) lbl "asm;" in
931
!g +> add_arc_opt (starti, newi);
934
| Ast_c.MacroStmt, ii ->
935
let newi = !g +> add_node (MacroStmt (stmt, ((),ii))) lbl "macro;" in
936
!g +> add_arc_opt (starti, newi);
940
(* ------------------------- *)
941
| Ast_c.NestedFunc def, ii ->
942
raise (Error NestedFunc)
950
and aux_statement_list starti (xi, newxi) statxs =
952
+> List.fold_left (fun starti statement_seq ->
953
if !Flag_parsing_c.label_strategy_2
954
then incr counter_for_labels;
957
if !Flag_parsing_c.label_strategy_2
958
then { newxi with labels = xi.labels @ [ !counter_for_labels ] }
962
match statement_seq with
963
| Ast_c.StmtElem statement ->
964
aux_statement (starti, newxi') statement
966
| Ast_c.CppDirectiveStmt directive ->
967
pr2_once ("ast_to_flow: filter a directive");
970
| Ast_c.IfdefStmt ifdef ->
971
pr2_once ("ast_to_flow: filter a directive");
974
| Ast_c.IfdefStmt2 (ifdefs, xxs) ->
976
let (head, body, tail) = Common.head_middle_tail ifdefs in
978
let newi = !g +> add_node (IfdefHeader (head)) newxi'.labels "[ifdef]" in
979
let taili = !g +> add_node (IfdefEndif (tail)) newxi'.labels "[endif]" in
980
!g +> add_arc_opt (starti, newi);
983
body +> List.map (fun elseif ->
985
!g +> add_node (IfdefElse (elseif)) newxi'.labels "[elseif]" in
986
!g#add_arc ((newi, elsei), Direct);
991
Common.zip (newi::elsenodes) xxs +> List.map (fun (start_nodei, xs)->
993
aux_statement_list (Some start_nodei) (newxi, newxi) xs in
994
!g +> add_arc_opt (finalthen, taili);
1002
(*****************************************************************************)
1003
(* Definition of function *)
1004
(*****************************************************************************)
1006
let (aux_definition: nodei -> definition -> unit) = fun topi funcdef ->
1008
let lbl_start = [!counter_for_labels] in
1010
let ({f_name = namefuncs;
1015
f_old_c_style = oldstyle;
1017
let iifunheader, iicompound =
1019
| ioparen::icparen::iobrace::icbrace::iifake::isto ->
1020
ioparen::icparen::iifake::isto,
1022
| _ -> raise Impossible
1026
let topstatement = Ast_c.Compound compound, iicompound in
1028
let headi = !g +> add_node
1030
Ast_c.f_name = namefuncs;
1034
f_body = [] (* empty body *);
1035
f_old_c_style = oldstyle;
1037
lbl_start ("function " ^ Ast_c.str_of_name namefuncs) in
1038
let enteri = !g +> add_node Enter lbl_0 "[enter]" in
1039
let exiti = !g +> add_node Exit lbl_0 "[exit]" in
1040
let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in
1042
!g#add_arc ((topi, headi), Direct);
1043
!g#add_arc ((headi, enteri), Direct);
1045
(* ---------------------------------------------------------------- *)
1046
(* todocheck: assert ? such as we have "consommer" tous les labels *)
1050
labels_assoc = compute_labels_and_create_them topstatement;
1052
errorexiti = Some errorexiti;
1053
compound_caller = FunctionDef;
1057
let lasti = aux_statement (Some enteri, info) topstatement in
1058
!g +> add_arc_opt (lasti, exiti)
1060
(*****************************************************************************)
1062
(*****************************************************************************)
1064
(* Helpers for SpecialDeclMacro.
1066
* could also force the coccier to define
1067
* the toplevel macro statement as in @@ toplevel_declarator MACRO_PARAM;@@
1068
* and so I would not need this hack and instead I would to a cleaner
1069
* match in cocci_vs_c_3.ml of a A.MacroTop vs B.MacroTop
1071
let specialdeclmacro_to_stmt (s, args, ii) =
1072
let (iis, iiopar, iicpar, iiptvirg) = tuple_of_list4 ii in
1073
let ident = Ast_c.RegularName (s, [iis]) in
1074
let identfinal = (Ast_c.Ident (ident), Ast_c.noType()), [] in
1075
let f = (Ast_c.FunCall (identfinal, args), Ast_c.noType()), [iiopar;iicpar] in
1076
let stmt = Ast_c.ExprStatement (Some f), [iiptvirg] in
1077
stmt, (f, [iiptvirg])
1081
let ast_to_control_flow e =
1083
(* globals (re)initialialisation *)
1084
g := (new ograph_mutable);
1085
counter_for_labels := 1;
1086
counter_for_braces := 0;
1087
counter_for_switch := 0;
1089
let topi = !g +> add_node TopNode lbl_0 "[top]" in
1092
| Ast_c.Definition ((defbis,_) as def) ->
1093
let _funcs = defbis.f_name in
1094
let _c = defbis.f_body in
1095
(* if !Flag.show_misc then pr2 ("build info function " ^ funcs); *)
1096
aux_definition topi def;
1099
| Ast_c.Declaration _
1100
| Ast_c.CppTop (Ast_c.Include _)
1105
| Ast_c.Declaration decl ->
1106
(Control_flow_c.Decl decl), "decl"
1107
| Ast_c.CppTop (Ast_c.Include inc) ->
1108
(Control_flow_c.Include inc), "#include"
1109
| Ast_c.MacroTop (s, args, ii) ->
1110
let (st, (e, ii)) = specialdeclmacro_to_stmt (s, args, ii) in
1111
(Control_flow_c.ExprStatement (st, (Some e, ii))), "macrotoplevel"
1112
(*(Control_flow_c.MacroTop (s, args,ii), "macrotoplevel") *)
1113
| _ -> raise Impossible
1115
let ei = !g +> add_node elem lbl_0 str in
1116
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1118
!g#add_arc ((topi, ei),Direct);
1119
!g#add_arc ((ei, endi),Direct);
1122
| Ast_c.CppTop (Ast_c.Define ((id,ii), (defkind, defval))) ->
1123
let s = ("#define " ^ id) in
1124
let headeri = !g+>add_node (DefineHeader ((id, ii), defkind)) lbl_0 s in
1125
!g#add_arc ((topi, headeri),Direct);
1128
| Ast_c.DefineExpr e ->
1129
let ei = !g +> add_node (DefineExpr e) lbl_0 "defexpr" in
1130
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1131
!g#add_arc ((headeri, ei) ,Direct);
1132
!g#add_arc ((ei, endi) ,Direct);
1134
| Ast_c.DefineType ft ->
1135
let ei = !g +> add_node (DefineType ft) lbl_0 "deftyp" in
1136
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1137
!g#add_arc ((headeri, ei) ,Direct);
1138
!g#add_arc ((ei, endi) ,Direct);
1140
| Ast_c.DefineStmt st ->
1142
(* can have some return; inside the statement *)
1143
let exiti = !g +> add_node Exit lbl_0 "[exit]" in
1144
let errorexiti = !g +> add_node ErrorExit lbl_0 "[errorexit]" in
1145
let goto_labels = compute_labels_and_create_them st in
1147
let info = { initial_info with
1148
labels_assoc = goto_labels;
1150
errorexiti = Some errorexiti;
1154
let lasti = aux_statement (Some headeri , info) st in
1155
lasti +> do_option (fun lasti ->
1156
(* todo? if don't have a lasti ? no EndNode ? CTL will work ? *)
1157
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1158
!g#add_arc ((lasti, endi), Direct)
1162
| Ast_c.DefineDoWhileZero ((st,_e), ii) ->
1164
!g +> add_node (DefineDoWhileZeroHeader ((),ii)) lbl_0 "do0" in
1165
!g#add_arc ((headeri, headerdoi), Direct);
1166
let info = initial_info in
1167
let lasti = aux_statement (Some headerdoi , info) st in
1168
lasti +> do_option (fun lasti ->
1169
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1170
!g#add_arc ((lasti, endi), Direct)
1173
| Ast_c.DefineFunction def ->
1174
aux_definition headeri def;
1176
| Ast_c.DefineText (s, s_ii) ->
1177
raise (Error(Define(pinfo_of_ii ii)))
1178
| Ast_c.DefineEmpty ->
1179
let endi = !g +> add_node EndNode lbl_0 "[end]" in
1180
!g#add_arc ((headeri, endi),Direct);
1181
| Ast_c.DefineInit _ ->
1182
raise (Error(Define(pinfo_of_ii ii)))
1183
| Ast_c.DefineTodo ->
1184
raise (Error(Define(pinfo_of_ii ii)))
1193
(*****************************************************************************)
1194
(* CFG loop annotation *)
1195
(*****************************************************************************)
1197
let annotate_loop_nodes g =
1198
let firsti = Control_flow_c.first_node g in
1200
(* just for opti a little *)
1201
let already = Hashtbl.create 101 in
1203
g +> Ograph_extended.dfs_iter_with_path firsti (fun xi path ->
1204
Hashtbl.add already xi true;
1205
let succ = g#successors xi in
1206
let succ = succ#tolist in
1207
succ +> List.iter (fun (yi,_edge) ->
1208
if Hashtbl.mem already yi && List.mem yi (xi::path)
1210
let node = g#nodes#find yi in
1211
let ((node2, nodeinfo), nodestr) = node in
1212
let node' = ((node2, {nodeinfo with is_loop = true}), (nodestr ^ "*"))
1214
g#replace_node (yi, node');
1222
(*****************************************************************************)
1224
(*****************************************************************************)
1226
(* the second phase, deadcode detection. Old code was raising DeadCode if
1227
* lasti = None, but maybe not. In fact if have 2 return in the then
1228
* and else of an if ?
1230
* alt: but can assert that at least there exist
1231
* a node to exiti, just check #pred of exiti.
1233
* Why so many deadcode in Linux ? Ptet que le label est utilisé
1234
* mais dans le corps d'une macro et donc on le voit pas :(
1237
let deadcode_detection g =
1239
g#nodes#iter (fun (k, node) ->
1240
let pred = g#predecessors k in
1242
(match unwrap node with
1245
* | EndStatement _ -> pr2 "deadcode sur fake node, pas grave";
1250
| Exit -> () (* if have 'loop: if(x) return; i++; goto loop' *)
1251
| SeqEnd _ -> () (* todo?: certaines '}' deviennent orphelins *)
1253
(match Control_flow_c.extract_fullstatement node with
1254
| Some (st, ii) -> raise (Error (DeadCode (Some (pinfo_of_ii ii))))
1255
| _ -> pr2 "CFG: orphelin nodes, maybe something weird happened"
1260
(*------------------------------------------------------------------------*)
1261
(* special_cfg_braces: the check are really specific to the way we
1262
* have build our control_flow, with the { } in the graph so normally
1263
* all those checks here are useless.
1265
* ver1: to better error reporting, to report earlier the message, pass
1266
* the list of '{' (containing morover a brace_identifier) instead of
1270
let (check_control_flow: cflow -> unit) = fun g ->
1272
let nodes = g#nodes in
1273
let starti = first_node g in
1274
let visited = ref (new oassocb []) in
1276
let print_trace_error xs = pr2 "PB with flow:"; Common.pr2_gen xs; in
1278
let rec dfs (nodei, (* Depth depth,*) startbraces, trace) =
1279
let trace2 = nodei::trace in
1280
if !visited#haskey nodei
1282
(* if loop back, just check that go back to a state where have same depth
1284
let (*(Depth depth2)*) startbraces2 = !visited#find nodei in
1285
if (*(depth = depth2)*) startbraces <> startbraces2
1288
pr2 (sprintf "PB with flow: the node %d has not same braces count"
1290
print_trace_error trace2
1293
let children = g#successors nodei in
1294
let _ = visited := !visited#add (nodei, (* Depth depth*) startbraces) in
1296
(* old: good, but detect a missing } too late, only at the end
1298
(match fst (nodes#find nodei) with
1299
| StartBrace i -> Depth (depth + 1)
1300
| EndBrace i -> Depth (depth - 1)
1306
(match unwrap (nodes#find nodei), startbraces with
1307
| SeqStart (_,i,_), xs -> i::xs
1308
| SeqEnd (i,_), j::xs ->
1313
pr2 (sprintf ("PB with flow: not corresponding match between }%d and excpeted }%d at node %d") i j nodei);
1314
print_trace_error trace2;
1317
| SeqEnd (i,_), [] ->
1318
pr2 (sprintf "PB with flow: too much } at }%d " i);
1319
print_trace_error trace2;
1326
if null children#tolist
1328
if (* (depth = 0) *) startbraces <> []
1329
then print_trace_error trace2
1331
children#tolist +> List.iter (fun (nodei,_) ->
1332
dfs (nodei, newdepth, trace2)
1336
dfs (starti, (* Depth 0*) [], [])
1338
(*****************************************************************************)
1340
(*****************************************************************************)
1342
let report_error error =
1343
let error_from_info info =
1344
Common.error_message_short info.file ("", info.charpos)
1347
| DeadCode infoopt ->
1349
| None -> pr2 "FLOW: deadcode detected, but cant trace back the place"
1350
| Some info -> pr2 ("FLOW: deadcode detected: " ^ error_from_info info)
1352
| CaseNoSwitch info ->
1353
pr2 ("FLOW: case without corresponding switch: " ^ error_from_info info)
1354
| OnlyBreakInSwitch info ->
1355
pr2 ("FLOW: only break are allowed in switch: " ^ error_from_info info)
1356
| NoEnclosingLoop (info) ->
1357
pr2 ("FLOW: can't find enclosing loop: " ^ error_from_info info)
1358
| GotoCantFindLabel (s, info) ->
1359
pr2 ("FLOW: cant jump to " ^ s ^ ": because we can't find this label")
1361
pr2 ("FLOW: can't find exit or error exit: " ^ error_from_info info)
1362
| DuplicatedLabel s ->
1363
pr2 ("FLOW: duplicate label" ^ s)
1365
pr2 ("FLOW: not handling yet nested function")
1367
pr2 ("FLOW: not handling computed goto yet")
1369
pr2 ("Unsupported form of #define: " ^ error_from_info info)