37
37
let warning s = Printf.fprintf stderr "warning: %s\n" s
39
39
type cocci_predicate = Lib_engine.predicate * Ast.meta_name Ast_ctl.modif
41
(cocci_predicate,Ast.meta_name, Wrapper_ctl.info) Ast_ctl.generic_ctl
40
type formula = Lib_engine.ctlcocci
41
type top_formula = NONDECL of Lib_engine.ctlcocci | CODE of Lib_engine.ctlcocci
43
43
let union = Common.union_set
44
44
let intersect l1 l2 = List.filter (function x -> List.mem x l2) l1
109
109
(* This stays being AX even for sgrep_mode, because it is used to identify
110
110
the structure of the term, not matching the pattern. *)
111
let ctl_back_ag = function
113
| CTL.False -> CTL.False
114
| x -> CTL.AG(CTL.BACKWARD,CTL.NONSTRICT,x)
111
116
let ctl_back_ax = function
112
117
CTL.True -> CTL.True
113
118
| CTL.False -> CTL.False
167
172
let aftpred = predmaker false (Lib_engine.After, CTL.Control)
168
173
let retpred = predmaker false (Lib_engine.Return, CTL.Control)
169
174
let funpred = predmaker false (Lib_engine.FunHeader, CTL.Control)
175
let unsbrpred = predmaker false (Lib_engine.UnsafeBrace, CTL.Control)
170
176
let toppred = predmaker false (Lib_engine.Top, CTL.Control)
171
177
let exitpred = predmaker false (Lib_engine.ErrorExit, CTL.Control)
172
178
let endpred = predmaker false (Lib_engine.Exit, CTL.Control)
445
453
let res = k re in
446
454
match Ast.unwrap re with
447
455
Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
448
bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
449
| Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
456
bind (mcode r ((),(),bef,[])) res
457
| Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,[])) res
464
472
let contains_pos =
465
473
let bind x y = x or y in
466
474
let option_default = false in
467
let mcode r (_,_,kind,metapos) =
469
Ast.MetaPos(_,_,_,_,_) -> true
470
| Ast.NoMetaPos -> false in
475
let mcode r (_,_,kind,metapos) = not (metapos = []) in
471
476
let do_nothing r k e = k e in
472
477
let rule_elem r k re =
473
478
let res = k re in
474
479
match Ast.unwrap re with
475
480
Ast.FunHeader(bef,_,fninfo,name,lp,params,rp) ->
476
bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
477
| Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,Ast.NoMetaPos)) res
481
bind (mcode r ((),(),bef,[])) res
482
| Ast.Decl(bef,_,decl) -> bind (mcode r ((),(),bef,[])) res
480
485
V.combiner bind option_default
801
806
let (br2,_) = get_after_e branch2 a in
802
807
(Ast.rewrap s (Ast.IfThenElse(ifheader,br1,els,br2,aft)),[Ast.Other s])
803
808
| Ast.While(header,body,aft) ->
804
let (bd,_) = get_after_e body a in
809
let (bd,_) = get_after_e body ((Ast.Other s) :: a) in
805
810
(Ast.rewrap s (Ast.While(header,bd,aft)),[Ast.Other s])
806
811
| Ast.For(header,body,aft) ->
807
let (bd,_) = get_after_e body a in
812
let (bd,_) = get_after_e body ((Ast.Other s) :: a) in
808
813
(Ast.rewrap s (Ast.For(header,bd,aft)),[Ast.Other s])
809
814
| Ast.Do(header,body,tail) ->
810
let (bd,_) = get_after_e body a in
815
let (bd,_) = get_after_e body ((Ast.Other s) :: a) in
811
816
(Ast.rewrap s (Ast.Do(header,bd,tail)),[Ast.Other s])
812
817
| Ast.Iterator(header,body,aft) ->
813
let (bd,_) = get_after_e body a in
818
let (bd,_) = get_after_e body ((Ast.Other s) :: a) in
814
819
(Ast.rewrap s (Ast.Iterator(header,bd,aft)),[Ast.Other s])
815
820
| Ast.Switch(header,lb,decls,cases,rb) ->
816
821
let index = count_nested_braces s in
1000
1005
(* no point to put a label on truepred etc; it is local to this construct
1001
1006
so it must have the same label *)
1003
[truepred None; recurse branch Tail new_quantified new_mquantified
1008
[truepred None; recurse branch NotTop Tail new_quantified new_mquantified
1004
1009
(Some (lv,used)) llabel slabel guard] in
1005
1010
let after_pred = aftpred None in
1006
1011
let or_cases after_branch =
1084
1089
(Common.minus_set (Ast.get_fvs els) new_quantified)
1085
1090
(header_match None guard els);
1086
recurse branch2 Tail new_quantified new_mquantified
1091
recurse branch2 NotTop Tail new_quantified new_mquantified
1087
1092
(Some (lv,used)) llabel slabel guard] in
1088
1093
let after_pred = aftpred None in
1089
1094
let or_cases after_branch =
1286
1291
| (Ast.MINUS(pos,inst,adj,l),after) ->
1287
1292
let (first_metamatch,last_metamatch,rest_metamatch) =
1289
[] -> (matcher(Ast.CONTEXT(pos,Ast.NOTHING)),CTL.True,matcher d)
1294
Ast.NOREPLACEMENT ->
1295
(matcher(Ast.CONTEXT(pos,Ast.NOTHING)),CTL.True,matcher d)
1290
1296
| _ -> (matcher d,
1291
matcher(Ast.MINUS(pos,inst,adj,[])),
1297
matcher(Ast.MINUS(pos,inst,adj,Ast.NOREPLACEMENT)),
1292
1298
ctl_and CTL.NONSTRICT
1293
1299
(ctl_not (make_raw_match label false ast))
1294
(matcher(Ast.MINUS(pos,inst,adj,[])))) in
1300
(matcher(Ast.MINUS(pos,inst,adj,Ast.NOREPLACEMENT)))) in
1295
1301
(* try to follow after link *)
1296
1302
let to_end = ctl_or (aftpred None) (loopfallpred None) in
1297
1303
let is_compound =
1311
1317
(CTL.HackForStmt(CTL.FORWARD,CTL.NONSTRICT,
1312
1318
ctl_and CTL.NONSTRICT label_pred
1313
1319
(make_raw_match label false ast),
1314
ctl_and CTL.NONSTRICT rest_metamatch prelabel_pred))
1320
ctl_and CTL.NONSTRICT prelabel_pred rest_metamatch))
1316
1322
let body f = ctl_and CTL.NONSTRICT label_pred (f ender) in
1317
1323
let stmt_fvs = Ast.get_fvs stmt in
1612
1618
(* --------------------------------------------------------------------- *)
1613
1619
(* the main translation loop *)
1615
let rec statement_list stmt_list after quantified minus_quantified
1621
let rec statement_list stmt_list top after quantified minus_quantified
1616
1622
label llabel slabel dots_before guard =
1618
1624
(* include Disj to be on the safe side *)
1621
1627
let compute_label l e db = if db or isdots e then l else None in
1622
1628
match Ast.unwrap stmt_list with
1624
let rec loop quantified minus_quantified dots_before label llabel slabel
1630
let rec loop top quantified minus_quantified dots_before
1626
1633
([],_,_) -> (match after with After f -> f | _ -> CTL.True)
1628
statement e after quantified minus_quantified
1635
statement e top after quantified minus_quantified
1629
1636
(compute_label label e dots_before)
1630
1637
llabel slabel guard
1631
1638
| (e::sl,fv::fvs,mfv::mfvs) ->
1647
1654
Ast.Goto _ -> (None,None,None)
1648
1655
| _ -> (label,llabel,slabel))
1649
1656
| _ -> (label,llabel,slabel) in
1650
loop new_quantified new_mquantified (isdots e)
1657
loop NotTop new_quantified new_mquantified (isdots e)
1651
1658
label1 llabel1 slabel1
1652
1659
(sl,fvs,mfvs)))
1653
1660
new_quantified new_mquantified
1654
1661
(compute_label label e dots_before) llabel slabel guard)
1655
1662
| _ -> failwith "not possible" in
1656
loop quantified minus_quantified dots_before
1663
loop top quantified minus_quantified dots_before
1657
1664
label llabel slabel
1658
1665
(x,List.map Ast.get_fvs x,List.map Ast.get_mfvs x)
1659
1666
| Ast.CIRCLES(x) -> failwith "not supported"
1732
1739
(Ast.MINUS(_,inst1,adj1,l1),Ast.MINUS(_,_,_,l2))
1733
1740
when !Flag.sgrep_mode2 ->
1734
1741
(* in sgrep mode, we can propagate the - *)
1735
Some (Ast.MINUS(Ast.NoPos,inst1,adj1,l1@l2))
1744
(Ast.NOREPLACEMENT,Ast.NOREPLACEMENT) ->
1747
failwith "no replacements allowed in sgrep mode" in
1748
Some (Ast.MINUS(Ast.NoPos,inst1,adj1,new_info))
1736
1749
| (Ast.MINUS(_,_,_,l1),Ast.MINUS(_,_,_,l2)) ->
1737
Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2,Ast.ONE)))
1752
(Ast.NOREPLACEMENT,Ast.NOREPLACEMENT) ->
1754
| (Ast.NOREPLACEMENT,Ast.REPLACEMENT(l,ct))
1755
| (Ast.REPLACEMENT(l,ct),Ast.NOREPLACEMENT) ->
1757
| (Ast.REPLACEMENT(l1,ct1),Ast.REPLACEMENT(l2,ct2)) ->
1758
Ast.BEFORE(l1@l2,Ast.lub_count ct1 ct2) in
1759
Some (Ast.CONTEXT(Ast.NoPos,change))
1738
1760
| (Ast.CONTEXT(_,Ast.BEFORE(l1,c1)),
1739
1761
Ast.CONTEXT(_,Ast.AFTER(l2,c2))) ->
1740
(if not (c1 = c2) then failwith "bad + code");
1741
Some (Ast.CONTEXT(Ast.NoPos,Ast.BEFORE(l1@l2,c1)))
1763
(Ast.CONTEXT(Ast.NoPos,
1764
Ast.BEFORE(l1@l2,Ast.lub_count c1 c2)))
1742
1765
| (Ast.CONTEXT(_,Ast.BEFORE(_)),Ast.CONTEXT(_,Ast.NOTHING))
1743
1766
| (Ast.CONTEXT(_,Ast.NOTHING),Ast.CONTEXT(_,Ast.NOTHING)) ->
1764
1787
ctl_or normal_res
1765
1788
(ctl_and (make_match mod_rbrace)
1770
(ctl_or simple_return return_expr))))
1772
1791
(make_match stripped_rbrace)
1773
1792
(* error exit not possible; it is in the middle
1774
1793
of code, so a return is needed *)
1795
(* worry about perf, but seems correct, not ax *)
1799
(ctl_or simple_return return_expr))))))
1777
1801
(* some change in the middle of the return, so have to
1778
1802
find an actual return *)
1894
1918
(* want AF even for sgrep *)
1895
1919
(CTL.AF(CTL.FORWARD,CTL.STRICT,end_brace))))
1896
1920
(quantify guard b2fvs
1897
(statement_list body Tail
1921
(statement_list body NotTop Tail
1898
1922
new_quantified2 new_mquantified2
1899
1923
None(*no label because past the goto*)
1900
1924
llabel slabel false guard))])) in
1916
1940
| Ast.Disj(stmt_dots_list) -> (* list shouldn't be empty *)
1917
1941
(*ctl_and seems pointless, disjuncts see label too
1918
1942
(label_pred_maker label)*)
1919
(List.fold_left ctl_seqor CTL.False
1922
statement_list sl after quantified minus_quantified label
1923
llabel slabel true guard)
1946
statement_list sl top after quantified minus_quantified label
1947
llabel slabel true guard)
1949
let safe_subformulas =
1951
Top -> List.map2 protect_top_level stmt_dots_list subformulas
1952
| NotTop -> subformulas in
1953
List.fold_left ctl_seqor CTL.False safe_subformulas
1926
1955
| Ast.Nest(starter,stmt_dots,ender,whencode,multi,bef,aft) ->
1927
1956
(* label in recursive call is None because label check is already
1948
1977
quantify guard bfvs
1949
1978
(let dots_pattern =
1950
statement_list stmt_dots (a2n after) new_quantified minus_quantified
1979
statement_list stmt_dots top (a2n after)
1980
new_quantified minus_quantified
1951
1981
label(*None*) llabel slabel true guard in
1952
1982
dots_and_nests multi
1953
1983
(Some dots_pattern) whencode bef aft dot_code after label
1954
1984
(process_bef_aft new_quantified minus_quantified
1955
1985
label(*None*) llabel slabel true)
1957
statement_list x Tail new_quantified minus_quantified label(*None*)
1986
(function x -> (* for when code *)
1987
statement_list x NotTop Tail
1988
new_quantified minus_quantified label(*None*)
1958
1989
llabel slabel true true)
1960
statement x Tail new_quantified minus_quantified label(*None*)
1990
(function x -> (* for when code *)
1991
statement x NotTop Tail
1992
new_quantified minus_quantified label(*None*)
1961
1993
llabel slabel true)
1962
1994
guard quantified
1963
1995
(function x -> Ast.set_fvs [] (Ast.rewrap stmt x)))
1973
2005
dots_and_nests false None whencodes bef aft dot_code after label
1974
2006
(process_bef_aft quantified minus_quantified None llabel slabel true)
1976
statement_list x Tail quantified minus_quantified
2008
statement_list x NotTop Tail quantified minus_quantified
1977
2009
None llabel slabel true true)
1979
statement x Tail quantified minus_quantified None llabel slabel true)
2011
statement x NotTop Tail quantified minus_quantified
2012
None llabel slabel true)
1980
2013
guard quantified
1981
2014
(function x -> Ast.set_fvs [] (Ast.rewrap stmt x))
2115
2148
let new3_quantified = union b1fvs new2_quantified in
2116
2149
let new3_mquantified = union mb1fvs new2_mquantified in
2118
statement_list body Tail
2151
statement_list body NotTop Tail
2119
2152
new3_quantified new3_mquantified (Some (lv,used)) llabel
2120
2153
(Some (lv,used)) false(*?*) guard in
2121
2154
quantify guard b1fvs (make_seq [case_header; body])
2224
2257
(CTL.FORWARD,guard_to_strict guard,start_brace,
2225
statement_list stmt_dots
2258
statement_list stmt_dots NotTop
2226
2259
(* discards match on right brace, but don't need it *)
2227
2260
(Guard (make_seq_after end_brace after))
2228
2261
new_quantified3 new_mquantified3
2303
2337
(match Ast.unwrap body with
2305
((_,i,(Ast.MINUS(_,_,_,[]) as d),_),[],_,_) ->
2339
((_,i,(Ast.MINUS(_,_,_,Ast.NOREPLACEMENT) as d),_),[],_,_) ->
2306
2340
(match (Ast.unwrap lbrace,Ast.unwrap rbrace) with
2307
(Ast.SeqStart((_,_,Ast.MINUS(_,_,_,[]),_)),
2308
Ast.SeqEnd((_,_,Ast.MINUS(_,_,_,[]),_)))
2341
(Ast.SeqStart((_,_,Ast.MINUS(_,_,_,Ast.NOREPLACEMENT),_)),
2342
Ast.SeqEnd((_,_,Ast.MINUS(_,_,_,Ast.NOREPLACEMENT),_)))
2309
2343
when not (contains_pos rbrace) ->
2311
2345
(* andany drops everything to the end, including close
2347
2381
| _ -> failwith "not possible" in
2348
2382
let define_header = quantify guard hfvs (make_match header) in
2349
2383
let body_code =
2350
statement_list body after
2384
statement_list body NotTop after
2351
2385
(Common.union_set bfvs quantified)
2352
2386
(Common.union_set mbfvs minus_quantified)
2353
2387
None llabel slabel true guard in
2369
2403
Ast.AddingBetweenDots (brace_term,n)
2370
2404
| Ast.DroppingBetweenDots (brace_term,n) ->
2371
2405
let match_brace =
2372
statement brace_term after quantified minus_quantified
2406
statement brace_term NotTop after quantified minus_quantified
2373
2407
label llabel slabel guard in
2374
2408
let v = Printf.sprintf "_r_%d" n in
2375
2409
let case1 = ctl_and CTL.NONSTRICT (CTL.Ref v) match_brace in
2391
2425
quantify true (get_unquantified quantified [n])
2392
2426
(ctl_and s (make_raw_match None guard re) paren_pred)
2393
2427
| Ast.Other s ->
2394
statement s Tail quantified minus_quantified label llabel slabel guard
2428
statement s NotTop Tail quantified minus_quantified
2429
label llabel slabel guard
2395
2430
| Ast.Other_dots d ->
2396
statement_list d Tail quantified minus_quantified
2431
statement_list d NotTop Tail quantified minus_quantified
2397
2432
label llabel slabel true guard
2434
and protect_top_level stmt_dots formula =
2435
let starts_with_dots =
2436
match Ast.undots stmt_dots with
2438
(match Ast.unwrap d with
2439
Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
2440
| Ast.Stars(_,_,_,_) -> true
2443
let starts_with_non_context_brace =
2445
Some false = OK except on function braces
2446
Some true = Never OK *)
2447
match Ast.undots stmt_dots with
2449
(match Ast.unwrap d with
2450
Ast.Seq(before,body,after) ->
2452
match Ast.unwrap before with
2453
Ast.SeqStart(obr) -> Ast.get_mcodekind obr
2454
| _ -> failwith "bad seq" in
2456
match Ast.unwrap after with
2457
Ast.SeqEnd(cbr) -> Ast.get_mcodekind cbr
2458
| _ -> failwith "bad seq"in
2459
(match (beforemc,aftermc) with
2461
(Ast.CONTEXT(_,(Ast.NOTHING|Ast.AFTER _)),
2462
Ast.CONTEXT(_,(Ast.NOTHING|Ast.BEFORE _))) -> None
2463
| (Ast.MINUS(_,_,_,Ast.NOREPLACEMENT),
2464
Ast.MINUS(_,_,_,Ast.NOREPLACEMENT))
2465
when List.length (Ast.undots body) = 1 -> Some false (*ok on if*)
2466
(* unsafe, can't be allowed to match fn top *)
2471
then (* EX because there is a loop on enter/top *)
2472
ctl_and CTL.NONSTRICT (toppred None) (ctl_ex formula)
2474
match starts_with_non_context_brace with
2477
ctl_and CTL.NONSTRICT
2478
(ctl_not(CTL.EX(CTL.BACKWARD,funpred None)))
2481
ctl_and CTL.NONSTRICT
2482
(ctl_not(CTL.EX(CTL.BACKWARD,unsbrpred None)))
2399
2486
(* --------------------------------------------------------------------- *)
2400
2487
(* cleanup: convert AX to EX for pdots.
2401
2488
Concretely: AX(A[...] & E[...]) becomes AX(A[...]) & EX(E[...])
2459
2546
used_after := ua;
2460
2547
saved := Ast.get_saved t;
2461
2548
let quantified = Common.minus_set (Common.union_set ua fuas) pos in
2462
quantify false quantified
2463
(match Ast.unwrap t with
2549
let (wrap,formula) =
2550
match Ast.unwrap t with
2464
2551
Ast.FILEINFO(old_file,new_file) -> failwith "not supported fileinfo"
2552
| Ast.NONDECL(stmt) ->
2466
2553
let unopt = elim_opt.V.rebuilder_statement stmt in
2467
2554
let unopt = preprocess_dots_e unopt in
2468
cleanup(statement unopt VeryEnd quantified [] None None None false)
2557
(statement unopt Top VeryEnd quantified [] None None None false) in
2558
((function x -> NONDECL x), formula)
2469
2559
| Ast.CODE(stmt_dots) ->
2470
2560
let unopt = elim_opt.V.rebuilder_statement_dots stmt_dots in
2471
2561
let unopt = preprocess_dots unopt in
2472
let starts_with_dots =
2473
match Ast.undots stmt_dots with
2475
(match Ast.unwrap d with
2476
Ast.Dots(_,_,_,_) | Ast.Circles(_,_,_,_)
2477
| Ast.Stars(_,_,_,_) -> true
2480
let starts_with_brace =
2481
match Ast.undots stmt_dots with
2483
(match Ast.unwrap d with
2488
statement_list unopt VeryEnd quantified [] None None None
2563
statement_list unopt Top VeryEnd quantified [] None None None
2491
(if starts_with_dots
2493
(* EX because there is a loop on enter/top *)
2494
ctl_and CTL.NONSTRICT (toppred None) (ctl_ex res)
2495
else if starts_with_brace
2497
ctl_and CTL.NONSTRICT
2498
(ctl_not(CTL.EX(CTL.BACKWARD,(funpred None)))) res
2500
| Ast.ERRORWORDS(exps) -> failwith "not supported errorwords")
2565
let clean_formula = cleanup (protect_top_level stmt_dots formula) in
2566
((function x -> CODE x), clean_formula)
2567
| Ast.ERRORWORDS(exps) -> failwith "not supported errorwords" in
2568
wrap (quantify false quantified formula)
2502
2570
(* --------------------------------------------------------------------- *)
2503
2571
(* Entry points *)
2530
2598
Ast.ScriptRule _ | Ast.InitialScriptRule _ | Ast.FinalScriptRule _ -> []
2531
2599
| Ast.CocciRule (a,b,c,_,Ast_cocci.Normal) ->
2532
2600
asttoctlz (a,b,c) used_after positions
2533
| Ast.CocciRule (a,b,c,_,Ast_cocci.Generated) -> [CTL.True]
2601
| Ast.CocciRule (a,b,c,_,Ast_cocci.Generated) -> [CODE CTL.True]
2535
2603
let pp_cocci_predicate (pred,modif) =
2536
2604
Pretty_print_engine.pp_predicate pred