diff --git a/src/plugins/dive/build.ml b/src/plugins/dive/build.ml index 80018f10e2d452295a9fa7e0bda651dc4e034de7..92a3ff2e6081271441e87b3f0206219a3c6aa30d 100644 --- a/src/plugins/dive/build.ml +++ b/src/plugins/dive/build.ml @@ -40,12 +40,107 @@ let rec list_break n l = (a :: l1, l2) +(* --- Lval enumeration --- *) + +module IterLval = +struct + let visitor f = + object + inherit Visitor.frama_c_inplace + method! vlval lval = f lval; SkipChildren + end + + let from_exp f exp = + ignore (Visitor.visitFramacExpr (visitor f) exp) + + let from_init f vi init = + ignore (Visitor.visitFramacInit (visitor f) vi NoOffset init) + + let from_alarm f = function + | Alarms.Division_by_zero e | Index_out_of_bound (e, _) | Invalid_shift (e,_) + | Overflow (_,e,_,_) | Float_to_int (e,_,_) | Is_nan_or_infinite (e,_) + | Is_nan (e,_) | Function_pointer (e,_) | Invalid_pointer e -> + from_exp f e + | Pointer_comparison (opt_e1,e2) -> + Extlib.may (from_exp f) opt_e1; + from_exp f e2 + | Differing_blocks (e1,e2) -> + from_exp f e1; from_exp f e2 + | Memory_access _ | Not_separated _ | Overlap _ + | Uninitialized _ | Dangling _ | Uninitialized_union _ -> () + | Invalid_bool lv -> f lv +end + + +(* --- Evaluation from analysis results --- *) + +module Eval = +struct + let to_kf_list kinstr expr = + let _,set = !Db.Value.expr_to_kernel_function kinstr ~deps:None expr in + Kernel_function.Hptset.fold (fun kf acc -> kf :: acc) set [] + + let to_cvalue kinstr lval = + let state = Db.Value.get_state kinstr in + let _,cvalue = !Db.Value.eval_lval None state lval in + cvalue + + let to_location kinstr lval = + let state = Db.Value.get_state kinstr in + !Db.Value.lval_to_loc_state state lval + + let to_zone kinstr lval = + !Db.Value.lval_to_zone kinstr lval + + let to_callstacks stmt = + let states = Db.Value.get_stmt_state_callstack ~after:false stmt in + match states with + | None -> assert false + | Some table -> + let module Table = Value_types.Callstack.Hashtbl in + Table.fold (fun cs _ acc -> cs :: acc) table [] + + let studia_is_direct (_,{Studia.Writes.direct}) = direct + + let writes kinstr lval = + let zone = to_zone kinstr lval in + Self.debug ~dkey "computing writes for %a" Cil_printer.pp_lval lval; + let result = Studia.Writes.compute zone in + let writes = Extlib.filter_map studia_is_direct fst result in + Self.debug ~dkey "%d found" (List.length writes); + writes + + let reads kinstr lval = + let zone = to_zone kinstr lval in + Self.debug ~dkey "computing reads for %a" Cil_printer.pp_lval lval; + let result = Studia.Reads.compute zone in + let reads = Extlib.filter_map studia_is_direct fst result in + Self.debug ~dkey "%d found" (List.length reads); + reads + + let does_cil_read_zone iter stmt cil zone = + let intersects lval = + let zone' = to_zone (Kstmt stmt) lval in + Locations.Zone.intersects zone' zone + in + try iter (fun lval -> if intersects lval then raise Exit) cil; false + with Exit -> true + + let does_exp_read_zone stmt exp zone = + does_cil_read_zone IterLval.from_exp stmt exp zone + + let does_init_read_zone stmt vi init zone = + does_cil_read_zone + (fun f init -> IterLval.from_init f vi init) + stmt init zone +end + + (* --- Precision evaluation --- *) let update_node_values node kinstr lval = - let typ = Cil.typeOfLval lval in - let state = Db.Value.get_state kinstr in - let _,cvalue = !Db.Value.eval_lval None state lval in + let typ = Cil.typeOfLval lval + and cvalue = Eval.to_cvalue kinstr lval in Graph.update_node_values node cvalue typ @@ -68,8 +163,7 @@ exception Unknown_location let enumerate_cells ~is_folded_base ~limit lval kinstr = (* If possible, refine the lval to a non-symbolic one *) let typ = Cil.typeOfLval lval in - let state = Db.Value.get_state kinstr in - let location = !Db.Value.lval_to_loc_state state lval in + let location = Eval.to_location kinstr lval in let open Locations in let add (acc,count) node_kind = if count >= limit then @@ -141,6 +235,21 @@ let build_node_locality callstack node_kind = | None -> { loc_file = get_loc_filename vi.vdecl ; loc_callstack = [] } +let find_compatible_callstacks stmt callstack = + let kf = Kernel_function.find_englobing_kf stmt in + if callstack <> [] && Kernel_function.equal kf (Callstack.top_kf callstack) + then + (* slight improvement which only work when there is no recursion + and which is only usefull because you currently can't have + all callstacks due to memexec -> in this particular case + we are sure not to miss the only admissible callstack *) + [callstack] + else + (* Keep only callstacks which are a compatible with the current one *) + let callstacks = Eval.to_callstacks stmt in + (* TODO: missing callstacks filtered by memexec *) + Callstack.filter_truncate callstacks callstack + (* --- Context object --- *) @@ -249,49 +358,22 @@ let build_alarm context callstack stmt alarm = let node_locality = build_node_locality callstack node_kind in add_node context ~node_kind ~node_locality -let build_node_deps context node = - let rec build_lval_write_deps callstack kinstr lval = - let zone = !Db.Value.lval_to_zone kinstr lval in - build_write_deps callstack zone - and build_write_deps callstack zone = + + +let build_node_writes context node = + + let rec build_write_deps callstack kinstr lval = let writes = match node.node_writes_computation with | Done -> [] | Partial writes -> writes | NotDone -> - Self.debug ~dkey "computing writes for %a" Node_kind.pretty node.node_kind; - let result = Studia.Writes.compute zone in - let is_direct (_,{Studia.Writes.direct}) = direct in - let writes = Extlib.filter_map is_direct fst result in - Self.debug ~dkey "%d found" (List.length writes); - node.node_writes_stmts <- writes; + let writes = Eval.writes kinstr lval in + node.node_writes_stmts <- writes @ build_arg_deps callstack; writes and add_deps = function | { skind=Instr instr } as stmt -> - let callstacks = - if callstack <> [] && - Kernel_function.(equal - (find_englobing_kf stmt) - (Callstack.top_kf callstack)) - then - (* slight improvement which only work when there is no recursion - and which is only usefull because you currently can't have - all callstacks due to memexec -> in this particular case - we are sure not to miss the only admissible callstack *) - [callstack] - else - (* Keep only callstacks which are a compatible with the current one *) - let states = Db.Value.get_stmt_state_callstack ~after:false stmt in - let callstacks = match states with - | None -> assert false - | Some table -> - let module Table = Value_types.Callstack.Hashtbl in - Table.fold (fun cs _ acc -> cs :: acc) table [] - in - (* TODO: missing callstacks filtered by memexec *) - Callstack.filter_truncate callstacks callstack - in - (* Create a dependency for each of them *) + let callstacks = find_compatible_callstacks stmt callstack in List.iter (fun cs -> build_instr_deps cs stmt instr) callstacks | _ -> assert false (* Studia invariant *) in @@ -299,28 +381,49 @@ let build_node_deps context node = List.iter add_deps sub; if rest = [] then Done else Partial rest - and build_arg_deps callstack vi = - assert vi.vformal; - let kf = Extlib.the (Kernel_function.find_defining_kf vi) in - let pos = Kernel_function.get_formal_position vi kf in - let callsites = - match Callstack.pop callstack with - | Some (kf',stmt,callstack) -> - assert (Kernel_function.equal kf' kf); - [(stmt,callstack)] - | None -> - let callsites = Kernel_function.find_syntactic_callsites kf in - List.map (fun (kf,stmt) -> (stmt,Callstack.init kf)) callsites - and add_deps (stmt,callstack) = - match stmt.skind with - | Instr (Call (_,_,args,_)) - | Instr (Local_init (_, ConsInit (_, args, _), _)) -> - let exp = List.nth args pos in - build_exp_deps callstack stmt Data exp - | _ -> - assert false (* Callsites can only be Call or ConsInit *) - in - List.iter add_deps callsites + and build_alarm_deps callstack stmt alarm = + IterLval.from_alarm (build_lval_deps callstack stmt Data) alarm + + and build_instr_deps callstack stmt = function + | Set (_, exp, _) -> + build_exp_deps callstack stmt Data exp + | Call (_, callee, args, _) -> + build_call_deps callstack stmt callee args + | Local_init (dest, ConsInit (f, args, k), loc) -> + let as_func _dest callee args _loc = + build_call_deps callstack stmt callee args + in + Cil.treat_constructor_as_func as_func dest f args k loc + | Local_init (vi, AssignInit init, _) -> + IterLval.from_init (build_lval_deps callstack stmt Data) vi init + | Asm _ | Skip _ | Code_annot _ -> () (* Cases not returned by Studia *) + + and build_arg_deps callstack = + match Node_kind.get_base node.node_kind with + (* TODO refine formal dependency computation for non-scalar formals *) + | Some vi when vi.vformal -> + let kf = Extlib.the (Kernel_function.find_defining_kf vi) in + let pos = Kernel_function.get_formal_position vi kf in + let callsites = + match Callstack.pop callstack with + | Some (kf',stmt,callstack) -> + assert (Kernel_function.equal kf' kf); + [(stmt,callstack)] + | None -> + let callsites = Kernel_function.find_syntactic_callsites kf in + List.map (fun (kf,stmt) -> (stmt,Callstack.init kf)) callsites + and add_deps (stmt,callstack) = + match stmt.skind with + | Instr (Call (_,_,args,_)) + | Instr (Local_init (_, ConsInit (_, args, _), _)) -> + let exp = List.nth args pos in + build_exp_deps callstack stmt Data exp + | _ -> + assert false (* Callsites can only be Call or ConsInit *) + in + List.iter add_deps callsites; + List.map fst callsites + | _ -> [] and build_return_deps callstack stmt args kf = match Kernel_function.find_return kf with @@ -342,64 +445,16 @@ let build_node_deps context node = Self.warning "Cannot compute all callee dependencies for %a" Cil_printer.pp_stmt stmt; end; - let kinstr = Kstmt stmt in - let _,set = !Db.Value.expr_to_kernel_function kinstr ~deps:None callee in - Kernel_function.Hptset.iter (build_return_deps callstack stmt args) set - - and build_alarm_deps callstack stmt alarm = - let for_exp e = - build_exp_deps callstack stmt Data e - in - let open Alarms in - match alarm with - | Division_by_zero e | Index_out_of_bound (e, _) | Invalid_shift (e,_) - | Overflow (_,e,_,_) | Float_to_int (e,_,_) | Is_nan_or_infinite (e,_) - | Is_nan (e,_) | Function_pointer (e,_) | Invalid_pointer e -> for_exp e - | Pointer_comparison (opt_e1,e2) -> Extlib.may for_exp opt_e1; for_exp e2 - | Differing_blocks (e1,e2) -> for_exp e1; for_exp e2 - | Memory_access _ | Not_separated _ | Overlap _ - | Uninitialized _ | Dangling _ | Uninitialized_union _ -> () - (* TODO: adress depencies inside lval *) - | Invalid_bool lv -> build_lval_deps callstack stmt Data lv - - and build_instr_deps callstack stmt = function - | Set (_, exp, _) -> - build_exp_deps callstack stmt Data exp - | Call (_, callee, args, _) -> build_call_deps callstack stmt callee args - | Local_init (dest, ConsInit (f, args, k), loc) -> - let as_func _dest callee args _loc = - build_call_deps callstack stmt callee args - in - Cil.treat_constructor_as_func as_func dest f args k loc - | Local_init (_, AssignInit init, _) -> - build_init_deps callstack stmt init - | Asm _ | Skip _ | Code_annot _ -> () (* Cases not returned by Studia *) - - and build_init_deps callstack stmt = function - | SingleInit exp -> - build_exp_deps callstack stmt Data exp - | CompoundInit (_typ, initl) -> - List.iter (fun (_off,init) -> build_init_deps callstack stmt init) initl + let l = Eval.to_kf_list (Kstmt stmt) callee in + List.iter (build_return_deps callstack stmt args) l and build_exp_deps callstack stmt kind exp = - match exp.enode with - | Const _ - | SizeOf _ | SizeOfE _ | SizeOfStr _ - | AlignOf _ | AlignOfE _ - | AddrOf _ | StartOf _ -> () - | Lval lval -> - build_lval_deps callstack stmt kind lval - | UnOp (_,e,_) | CastE (_,e) | Info (e,_) -> - build_exp_deps callstack stmt kind e - | BinOp (_,e1,e2,_) -> - build_exp_deps callstack stmt kind e1; - build_exp_deps callstack stmt kind e2 + IterLval.from_exp (build_lval_deps callstack stmt kind) exp and build_lval_deps callstack stmt kind lval = let kinstr = Kstmt stmt in let dst = build_lval context callstack kinstr lval in - Graph.create_dependency ~allow_folding:true - context.graph kinstr dst kind node + Graph.create_dependency context.graph kinstr dst kind node and build_scattered_deps callstack kinstr lval = let succ_count = List.length (Graph.pred context.graph node) in @@ -409,23 +464,19 @@ let build_node_deps context node = in let kind = Composition in let add_dep dst = - Graph.create_dependency ~allow_folding:true - context.graph kinstr dst kind node + Graph.create_dependency context.graph kinstr dst kind node in List.iter add_dep nodes; if complete then Done else NotDone in - update_node context node; let callstack = node.node_locality.loc_callstack in let writes_computation = match node.node_kind with | Scalar (vi,_typ,offset) -> - let lval = (Cil_types.Var vi, offset) in - build_lval_write_deps callstack Kglobal lval + build_write_deps callstack Kglobal (Cil_types.Var vi, offset) | Composite (vi) -> - let lval = (Cil_types.Var vi, Cil_types.NoOffset) in - build_lval_write_deps callstack Kglobal lval + build_write_deps callstack Kglobal (Cil_types.Var vi, Cil_types.NoOffset) | Scattered (lval,kinstr) -> build_scattered_deps callstack kinstr lval | Alarm (stmt,alarm) -> @@ -435,11 +486,123 @@ let build_node_deps context node = Done in node.node_writes_computation <- writes_computation; - begin match Node_kind.get_base node.node_kind with - (* TODO refine formal dependency computation for non-scalar formals *) - | Some vi when vi.vformal -> build_arg_deps callstack vi + update_node context node + + +let build_node_reads context node = + let rec build_reads_deps callstack kinstr lval = + let reads = match node.node_reads_computation with + | Done -> [] + | Partial reads -> reads + | NotDone -> Eval.reads kinstr lval + and add_deps stmt = + let zone = Some (Eval.to_zone kinstr lval) in + let callstacks = find_compatible_callstacks stmt callstack in + List.iter (fun cs -> build_stmt_deps cs zone stmt) callstacks + in + let sub,rest = list_break context.max_dep_fetch_count reads in + List.iter add_deps sub; + if rest = [] then Done else Partial rest + + and exp_contains_read zone stmt exp = + match zone with + | None -> true + | Some zone' -> + Eval.does_exp_read_zone stmt exp zone' + + and init_contains_read zone stmt vi init = + match zone with + | None -> true + | Some zone' -> + Eval.does_init_read_zone stmt vi init zone' + + and build_kinstr_deps callstack zone = function + | Kglobal -> () (* Do nothing *) + | Kstmt stmt -> build_stmt_deps callstack zone stmt + + and build_stmt_deps callstack zone stmt = + match stmt.skind with + | Instr instr -> build_instr_deps callstack zone stmt instr + | Return (Some exp,_) -> + if exp_contains_read zone stmt exp then + build_return_deps callstack stmt | _ -> () - end + + and build_instr_deps callstack zone stmt = function + | Set (lval, exp, _) -> + if exp_contains_read zone stmt exp then + build_lval_deps callstack stmt lval + | Local_init (dest, ConsInit (f, args, k), loc) -> + let as_func _dest callee args _loc = + build_call_deps callstack zone stmt callee args + in + Cil.treat_constructor_as_func as_func dest f args k loc + | Local_init (vi, AssignInit init, _) -> + if init_contains_read zone stmt vi init then + build_var_deps callstack stmt vi + | Call (_, callee, args, _) -> + build_call_deps callstack zone stmt callee args + | _ -> () + + and build_return_deps callstack stmt = + let kf = Kernel_function.find_englobing_kf stmt in + let callsites = + match Callstack.pop callstack with + | Some (kf',stmt,callstack) -> + assert (Kernel_function.equal kf' kf); + [(stmt,callstack)] + | None -> + let callsites = Kernel_function.find_syntactic_callsites kf in + List.map (fun (kf,stmt) -> (stmt,Callstack.init kf)) callsites + and add_deps (stmt,callstack) = + match stmt.skind with + | Instr (Call (None,_,_,_)) -> () + | Instr (Call (Some lval,_,_,_)) -> + build_lval_deps callstack stmt lval + | Instr (Local_init (vi,_,_)) -> + build_var_deps callstack stmt vi + | _ -> + assert false (* Callsites can only be Call or ConsInit *) + in + List.iter add_deps callsites; + + and build_call_deps callstack zone stmt callee args = + let l = Eval.to_kf_list (Kstmt stmt) callee in + List.iter (build_args_deps callstack zone stmt args) l + + and build_args_deps callstack zone stmt args callee_kf = + let callstack = Callstack.push (callee_kf,stmt) callstack in + let formals = Kernel_function.get_formals callee_kf in + List.iter2 (build_arg_dep callstack stmt zone) args formals + + and build_arg_dep callstack stmt zone arg formal = + if exp_contains_read zone stmt arg then + build_var_deps callstack stmt formal + + and build_lval_deps callstack stmt lval = + let kinstr = Kstmt stmt in + let src = build_lval context callstack kinstr lval in + Graph.create_dependency context.graph kinstr node Data src + + and build_var_deps callstack stmt vi = + build_lval_deps callstack stmt (Cil.var vi) + + in + let callstack = node.node_locality.loc_callstack in + let reads_computation = + match node.node_kind with + | Scalar (vi,_typ,offset) -> + build_reads_deps callstack Kglobal (Cil_types.Var vi, offset) + | Composite (vi) -> + build_reads_deps callstack Kglobal (Cil_types.Var vi, Cil_types.NoOffset) + | Scattered (_lval,kinstr) -> + build_kinstr_deps callstack None kinstr; + Done + | Alarm _ | Unknown _ | AbsoluteMemory | String _ | Error _ -> + Done + in + node.node_reads_computation <- reads_computation; + update_node context node (* --- Graph initialization --- *) @@ -491,28 +654,38 @@ let hide_base context vi = let unhide_base context vi = context.hidden_bases <- BaseSet.add vi context.hidden_bases -let explore ~depth context root = - context.graph_diff <- { context.graph_diff with last_root = Some root }; - let should_auto_explore node = - let is_root = Graph.Node.equal node root (* the root is always explored *) - and is_intersting_kind = match node.node_kind with - | Scattered _ -> false - | _ -> true - in - is_root || (not node.node_hidden && is_intersting_kind) - in - (* Breadth first search *) +let should_explore node = + match node.node_kind with + | Scattered _ -> false + | _ -> not node.node_hidden + +let bfs ~depth ~iter_succ f root = let queue : (node * int) Queue.t = Queue.create () in Queue.add (root,0) queue; while not (Queue.is_empty queue) do let (n,d) = Queue.take queue in - if d <= depth then begin - if n.node_writes_computation <> Done && should_auto_explore n then - build_node_deps context n; - Graph.iter_pred (fun n' -> Queue.add (n',d+1) queue) context.graph n; - end; + f n d; + if d < depth then + iter_succ (fun n' -> Queue.add (n',d+1) queue) n done +let explore_backward ~depth context root = + context.graph_diff <- { context.graph_diff with last_root = Some root }; + let iter_succ f n = Graph.iter_pred f context.graph n + and explore_node n d = + if n.node_writes_computation <> Done && (should_explore n || d <= 0) then + build_node_writes context n + in + bfs ~depth ~iter_succ explore_node root + +let explore_forward ~depth context root = + let iter_succ f n = Graph.iter_succ f context.graph n + and explore_node n d = + if n.node_reads_computation <> Done && (should_explore n || d <= 0) then + build_node_reads context n; + in + bfs ~depth ~iter_succ explore_node root + let complete context root = context.roots <- root :: context.roots; root @@ -604,7 +777,7 @@ let reduce_to_horizon ({ graph } as context) range new_root = let show context node = if node.node_hidden then begin node.node_hidden <- false; - explore ~depth:0 context node + explore_backward ~depth:0 context node end let hide context node = diff --git a/src/plugins/dive/build.mli b/src/plugins/dive/build.mli index 297805460174b83978b337a5c9efd25b4281d2f1..48e725ec93c920e84cbbaf8191fcbcdc7bd839ff 100644 --- a/src/plugins/dive/build.mli +++ b/src/plugins/dive/build.mli @@ -47,7 +47,8 @@ val add_stmt : t -> stmt -> node option val add_property : t -> Property.t -> node option val add_localizable : t -> Printer_tag.localizable -> node option -val explore : depth:int -> t -> node -> unit +val explore_forward : depth:int -> t -> node -> unit +val explore_backward : depth:int -> t -> node -> unit val show : t -> node -> unit val hide : t -> node -> unit diff --git a/src/plugins/dive/dive_graph.ml b/src/plugins/dive/dive_graph.ml index c8ecf5d5000975f44d62bf37b06ec9b57bf3d510..c6b7bf4ace1d5d283d1dd4ce2d9acc837c007ae9 100644 --- a/src/plugins/dive/dive_graph.ml +++ b/src/plugins/dive/dive_graph.ml @@ -39,7 +39,6 @@ struct let default = { dependency_key = -1; dependency_kind = Data; - dependency_multiple = false; dependency_origins = [] } end @@ -67,6 +66,7 @@ let create_node ~node_kind ~node_locality g = node_values = None; node_range = Empty; node_writes_computation = NotDone; + node_reads_computation = NotDone; node_writes_stmts = []; } in @@ -81,27 +81,21 @@ let update_node_values node new_values typ = node.node_range <- Node_range.(upper_bound node.node_range (evaluate new_values typ)) -let create_dependency ~allow_folding g kinstr v1 dependency_kind v2 = +let create_dependency g kinstr v1 dependency_kind v2 = let same_kind (_,e,_) = e.dependency_kind = dependency_kind in let matching_edge = try - if allow_folding then - Some (List.find same_kind (G.find_all_edges g v1 v2)) - else - None + Some (List.find same_kind (G.find_all_edges g v1 v2)) with Not_found -> None in let e = match matching_edge with - | Some (_,e,_) -> - e.dependency_multiple <- true; - e + | Some (_,e,_) -> e | None -> let e = { dependency_key = fresh_key (); dependency_kind; - dependency_multiple = false; dependency_origins = [] } in @@ -241,9 +235,9 @@ let ouptput_to_dot out_channel g = let kind_attribute = match e.dependency_kind with | Callee -> [`Color 0x00ff00 ] | _ -> [] - and folding_attribute = match e.dependency_multiple with - | true -> [ `Style `Bold ] - | false -> [] + and folding_attribute = match e.dependency_origins with + | [] | [_] -> [ `Style `Bold ] + | _ -> [] in kind_attribute @ folding_attribute end) in @@ -337,7 +331,6 @@ struct ("src", `Int n1.node_key) ; ("dst", `Int n2.node_key) ; ("kind", output_dep_kind dep.dependency_kind) ; - ("multiple", `Bool dep.dependency_multiple) ; ("origins", `List (List.map output_stmt dep.dependency_origins)) ; ] diff --git a/src/plugins/dive/dive_graph.mli b/src/plugins/dive/dive_graph.mli index e093170794fee6dad01050f4c839f57058094812..63e7b40e029b4df0757ac255e8a8a1bedefe894b 100644 --- a/src/plugins/dive/dive_graph.mli +++ b/src/plugins/dive/dive_graph.mli @@ -40,7 +40,7 @@ val remove_node : t -> node -> unit val update_node_values : node -> Cvalue.V.t -> Cil_types.typ -> unit -val create_dependency : allow_folding:bool -> t -> Cil_types.kinstr -> +val create_dependency : t -> Cil_types.kinstr -> node -> dependency_kind -> node -> unit val remove_dependency : t -> node * dependency * node -> unit diff --git a/src/plugins/dive/dive_types.mli b/src/plugins/dive/dive_types.mli index 3fcfe0e87c93466d52121cff220c3f90d4b0db07..0f8e23960b9c888d921f0889a7390c51cfad8720 100644 --- a/src/plugins/dive/dive_types.mli +++ b/src/plugins/dive/dive_types.mli @@ -51,6 +51,7 @@ type node = { mutable node_values : Cvalue.V.t option; mutable node_range : node_range; mutable node_writes_computation : (Cil_types.stmt list) computation; + mutable node_reads_computation : (Cil_types.stmt list) computation; mutable node_writes_stmts : Cil_types.stmt list; } @@ -59,7 +60,6 @@ type dependency_kind = Callee | Data | Address | Control | Composition type dependency = { dependency_key : int; dependency_kind : dependency_kind; - mutable dependency_multiple : bool; mutable dependency_origins : Cil_types.stmt list; } diff --git a/src/plugins/dive/main.ml b/src/plugins/dive/main.ml index bab0f137e0b1dc06b51ac1d8110872746ac9b584..acc8011ba63eb0e61d2ad13aac663eb50f730a9d 100644 --- a/src/plugins/dive/main.ml +++ b/src/plugins/dive/main.ml @@ -44,14 +44,14 @@ let main () = (* Add targeted vars to it *) let add_var vi = let node = Build.add_var context vi in - Build.explore ~depth context node + Build.explore_backward ~depth context node in Self.FromBases.iter add_var; (* Add alarms *) let add_alarm _emitter kf stmt ~rank:_ alarm _code_annot = if Self.FromFunctionAlarms.mem kf then begin let node = Build.add_alarm context stmt alarm in - Build.explore ~depth context node + Build.explore_backward ~depth context node end in if not (Self.FromFunctionAlarms.is_empty ()) then diff --git a/src/plugins/dive/server_interface.ml b/src/plugins/dive/server_interface.ml index 847558a2db7335a01ef06b1420aa7eaf505451d2..af50ee49d3abb88cada025e22092cbaa07e48ba4 100644 --- a/src/plugins/dive/server_interface.ml +++ b/src/plugins/dive/server_interface.ml @@ -219,7 +219,6 @@ struct "src", NodeId.syntax ; "dst", NodeId.syntax ; "kind", Syntax.string ; - "multiple", Syntax.boolean ; "origins", Syntax.array Kernel_ast.Marker.syntax ] @@ -272,9 +271,11 @@ let finalize' context node_opt = begin match node_opt with | None -> () | Some node -> - let depth = !global_window.perception.backward + let depth_backward = !global_window.perception.backward + and depth_forward = !global_window.perception.forward and horizon = !global_window.horizon in - Build.explore ~depth context node; + Build.explore_backward ~depth:depth_backward context node; + Build.explore_forward ~depth:depth_forward context node; if Extlib.has_some horizon.forward || Extlib.has_some horizon.backward then diff --git a/src/plugins/dive/tests/dive/callstack_global.i b/src/plugins/dive/tests/dive/callstack_global.i new file mode 100644 index 0000000000000000000000000000000000000000..22ef499b33e039a853afd5084f826209478a9d34 --- /dev/null +++ b/src/plugins/dive/tests/dive/callstack_global.i @@ -0,0 +1,17 @@ +/* run.config +STDOPT: +"-dive-from-variables main::r -dive-depth-limit 10" +*/ + +int g; + +float f(float x) { + g = g + x; + return g; +} + +void main(float a) +{ + int x1 = 3; + int x2 = 39; + int r = f(x1) + f(x2); +} diff --git a/src/plugins/dive/tests/dive/oracle/callstack_global.dot b/src/plugins/dive/tests/dive/oracle/callstack_global.dot new file mode 100644 index 0000000000000000000000000000000000000000..3ed012849b48cc45ef0f7e7402ca03123c8d26ff --- /dev/null +++ b/src/plugins/dive/tests/dive/oracle/callstack_global.dot @@ -0,0 +1,42 @@ +digraph G { + cp1 [label=<r>, shape=box, ]; + cp2 [label=<tmp>, shape=box, fillcolor="#AACCFF", color="#88AAFF", + style="filled", ]; + cp4 [label=<tmp_0>, shape=box, fillcolor="#AACCFF", color="#88AAFF", + style="filled", ]; + cp6 [label=<__retres>, shape=box, fillcolor="#EEFFEE", color="#004400", + style="filled", ]; + cp8 [label=<__retres>, shape=box, fillcolor="#EEFFEE", color="#004400", + style="filled", ]; + cp10 [label=<g>, shape=box, fillcolor="#EEFFEE", color="#004400", + style="filled", ]; + cp14 [label=<x>, shape=box, fillcolor="#EEFFEE", color="#004400", + style="filled", ]; + cp16 [label=<x2>, shape=box, fillcolor="#AACCFF", color="#88AAFF", + style="filled", ]; + cp18 [label=<x1>, shape=box, fillcolor="#AACCFF", color="#88AAFF", + style="filled", ]; + + subgraph cluster_cs_1 { label=<main>; cp18;cp16;cp4;cp2;cp1; + subgraph cluster_cs_2 { label=<f>; cp6; + }; + subgraph cluster_cs_3 { label=<f>; cp8; + }; + }; + subgraph cluster_cs_4 { label=<f>; cp14; + }; + subgraph cluster_file_1 { label=<tests/dive/callstack_global.i>; cp10; + }; + + cp2 -> cp1; + cp4 -> cp1; + cp6 -> cp2; + cp8 -> cp4; + cp10 -> cp6; + cp10 -> cp8; + cp10 -> cp10 [style="bold", ]; + cp14 -> cp10 [style="bold", ]; + cp16 -> cp14; + cp18 -> cp14; + + } \ No newline at end of file diff --git a/src/plugins/dive/tests/dive/oracle/callstack_global.res.oracle b/src/plugins/dive/tests/dive/oracle/callstack_global.res.oracle new file mode 100644 index 0000000000000000000000000000000000000000..303837be7b7a5c6bebd4ed9418bbe54f5c46fe67 --- /dev/null +++ b/src/plugins/dive/tests/dive/oracle/callstack_global.res.oracle @@ -0,0 +1,17 @@ +[kernel] Parsing tests/dive/callstack_global.i (no preprocessing) +[eva] Analyzing a complete application starting at main +[eva] Computing initial state +[eva] Initial state computed +[eva] done for function main +[eva:summary] ====== ANALYSIS SUMMARY ====== + ---------------------------------------------------------------------------- + 2 functions analyzed (out of 2): 100% coverage. + In these functions, 10 statements reached (out of 10): 100% coverage. + ---------------------------------------------------------------------------- + No errors or warnings raised during the analysis. + ---------------------------------------------------------------------------- + 0 alarms generated by the analysis. + ---------------------------------------------------------------------------- + No logical properties have been reached by the analysis. + ---------------------------------------------------------------------------- +[dive] output to tests/dive/result/callstack_global.dot diff --git a/src/plugins/studia/reads.ml b/src/plugins/studia/reads.ml index 5f7d21197ceaaaa6154ec7dea556cd8636eed2fe..6a17e2cafe4fb2d7bdba0f57e0f92b81b1588a00 100644 --- a/src/plugins/studia/reads.ml +++ b/src/plugins/studia/reads.ml @@ -62,7 +62,7 @@ class find_read zlval = object if Zone.intersects inputs zlval then if !Db.Value.use_spec_instead_of_definition kf then (* Direst, as there is no body for this funtion. *) - { effects with direct = true } + { effects with direct = true } else { effects with indirect = true } (* Indirect effect *) else @@ -78,7 +78,7 @@ class find_read zlval = object match stmt.skind with | Instr (Call (lvopt, f, args, loc)) -> aux_call lvopt f args loc; - Cil.SkipChildren + Cil.SkipChildren | Instr (Local_init(v, ConsInit(f, args, k), l)) -> Cil.treat_constructor_as_func aux_call v f args k l; Cil.SkipChildren