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
|
(*
* This file is part of Coccinelle, licensed under the terms of the GPL v2.
* See copyright.txt in the Coccinelle source code for more information.
* The Coccinelle source code can be obtained at http://coccinelle.lip6.fr
*)
(* This phase sets the safe_for_multi_decls field, which is normally false,
to true for transformations on declarations where the only change is on the
declared variable. This is the only kind of change on such a declaration
that can safely be done without splitting the declaration.
This also now allows complete removal of a declaration, with no changes
inside. This is related to the danger data type and the code in
parsing_c/danger.ml *)
module Ast = Ast_cocci
module V = Visitor_ast
(* ------------------------------------------------------------------------- *)
(* check if everything is removed, with no additions allowed *)
let lub x y =
match (x,y) with
(Ast.Unsafe,_) | (_,Ast.Unsafe) -> Ast.Unsafe
| (Ast.NoStorage,_) | (_,Ast.NoStorage) -> Ast.NoStorage
| _ -> Ast.Safe
let all_removed_recursor =
let bind x y = lub x y in
let option_default = Ast.Safe in
let do_nothing r k e = k e in
let mcode _ (_,_,kind,_) =
match kind with
Ast.MINUS(_,_,_,Ast.NOREPLACEMENT) -> Ast.Safe
| Ast.MINUS(_,_,_,Ast.REPLACEMENT(_,Ast.MANY)) -> Ast.NoStorage
| Ast.MINUS(_,_,_,Ast.REPLACEMENT(_,_)) -> Ast.Unsafe
| Ast.PLUS _ -> failwith "not possible"
| Ast.CONTEXT(_,info) -> Ast.Unsafe in
V.combiner bind option_default
mcode mcode mcode mcode mcode mcode mcode mcode mcode
mcode mcode mcode mcode mcode
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing
let all_removed_decl =
all_removed_recursor.V.combiner_declaration
let all_removed_field =
all_removed_recursor.V.combiner_field
(* ------------------------------------------------------------------------- *)
let mcode _ (_,_,kind,_) =
match kind with
Ast.MINUS(_,_,_,_) -> true
| Ast.PLUS _ -> failwith "not possible"
| Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING)
(* The mcode is a fake one before a decl or field. Only need to check
for additions here. Replacement will affect decl or field instead. *)
let add_on_mcode _ (_,_,kind,_) =
match kind with
Ast.MINUS(_,_,_,_) -> false
| Ast.PLUS _ -> failwith "not possible"
| Ast.CONTEXT(_,info) -> not (info = Ast.NOTHING)
let contains_modif =
let bind x y = x || y in
let option_default = false in
let do_nothing r k e = k e in
let annotated_decl decl =
match Ast.unwrap decl with
Ast.DElem(bef,_,_) -> bef in
let rule_elem r k re =
(* Very obscure how this could arise. Array type contains an expression
and the expression could contain a statement. *)
let res = k re in
match Ast.unwrap re with
Ast.FunHeader(bef,_,fninfo,name,lp,params,va,rp) ->
bind (mcode r ((),(),bef,[])) res
| Ast.Decl decl ->
bind (mcode r ((),(),annotated_decl decl,[])) res
| Ast.ForHeader(fr,lp,Ast.ForDecl(decl),e2,sem2,e3,rp) ->
bind (mcode r ((),(),annotated_decl decl,[])) res
| _ -> res in
let init r k i =
let res = k i in
match Ast.unwrap i with
Ast.StrInitList(allminus,_,_,_,_) -> allminus || res
| _ -> res in
let recursor =
V.combiner bind option_default
mcode mcode mcode mcode mcode mcode mcode mcode mcode
mcode mcode mcode mcode mcode
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing do_nothing do_nothing do_nothing do_nothing
do_nothing do_nothing init do_nothing
do_nothing do_nothing do_nothing do_nothing
do_nothing rule_elem do_nothing do_nothing do_nothing do_nothing in
recursor.V.combiner_fullType
let decl r k e =
let e = k e in
match all_removed_decl e with
Ast.Safe -> {e with Ast.safe_for_multi_decls = Ast.Safe}
| Ast.NoStorage -> {e with Ast.safe_for_multi_decls = Ast.NoStorage}
| Ast.Unsafe ->
match Ast.unwrap e with
Ast.Init(stg,ty,_,attr,_,_,sem)
| Ast.UnInit(stg,ty,_,attr,sem) ->
let stg_modif =
match stg with
Some stg -> mcode () stg
| None -> false in
let attr_modif = List.exists (mcode ()) attr in
let ft_modif = contains_modif ty in
let sem_modif = mcode () sem in
if not(stg_modif || attr_modif || ft_modif || sem_modif)
then {e with Ast.safe_for_multi_decls = Ast.Safe}
else e
| _ -> e
let anndecl r k e =
let e = k e in
match Ast.unwrap e with
Ast.DElem(bef,allminus,decl) ->
let bef_modif = add_on_mcode () ((),(),bef,[]) in
if bef_modif && not(decl.Ast.safe_for_multi_decls = Ast.Unsafe)
then (* not actually safe *)
Ast.rewrap e
(Ast.DElem(bef,allminus,
{decl with Ast.safe_for_multi_decls = Ast.Unsafe}))
else e
let field r k e =
let e = k e in
match all_removed_field e with
Ast.Safe -> {e with Ast.safe_for_multi_decls = Ast.Safe}
| Ast.NoStorage -> {e with Ast.safe_for_multi_decls = Ast.NoStorage}
| Ast.Unsafe ->
match Ast.unwrap e with
Ast.Field(ty,_,_bf,sem) ->
let ft_modif = contains_modif ty in
let sem_modif = mcode () sem in
if not(ft_modif || sem_modif)
then {e with Ast.safe_for_multi_decls = Ast.Safe}
else e
| _ -> e
let annfield r k e =
let e = k e in
match Ast.unwrap e with
Ast.FElem(bef,allminus,fld) ->
let bef_modif = add_on_mcode () ((),(),bef,[]) in
if bef_modif && not(fld.Ast.safe_for_multi_decls = Ast.Unsafe)
then (* not actually safe *)
Ast.rewrap e
(Ast.FElem(bef,allminus,
{fld with Ast.safe_for_multi_decls = Ast.Unsafe}))
else e
| _ -> e
let mcode e = e
let donothing r k e = k e
let process =
let fn = V.rebuilder
mcode mcode mcode mcode mcode mcode mcode mcode mcode
mcode mcode mcode mcode mcode
donothing donothing donothing donothing donothing donothing donothing
donothing donothing donothing donothing donothing donothing donothing
donothing donothing donothing decl anndecl field annfield
donothing donothing donothing donothing donothing in
List.map fn.V.rebuilder_top_level
let safe_for_multi_decls rules =
List.map
(function (mv,r) ->
(mv,
match r with
Ast.ScriptRule _
| Ast.InitialScriptRule _ | Ast.FinalScriptRule _ -> r
| Ast.CocciRule (nm, rule_info, r, is_exp,ruletype) ->
Ast.CocciRule(nm, rule_info,process r,is_exp,ruletype)))
rules
|