Skip to content
Snippets Groups Projects
Commit e4ba69e0 authored by Valentin Perrelle's avatar Valentin Perrelle Committed by David Bühler
Browse files

[Nonterm] Use the new Eva API

parent 2faaf0d7
No related branches found
No related tags found
No related merge requests found
...@@ -181,7 +181,7 @@ class unreachable_stmt_visitor kf to_ignore = object ...@@ -181,7 +181,7 @@ class unreachable_stmt_visitor kf to_ignore = object
method! vstmt stmt = method! vstmt stmt =
if Stmt.Hptset.mem stmt syntactically_reachable && if Stmt.Hptset.mem stmt syntactically_reachable &&
Db.Value.is_reachable_stmt stmt = false && not (Eva.Results.is_reachable stmt) &&
not (Stmt.Hptset.mem stmt !semantically_considered) not (Stmt.Hptset.mem stmt !semantically_considered)
then begin then begin
(* add node and its reachable successors to the considered statements *) (* add node and its reachable successors to the considered statements *)
...@@ -197,11 +197,10 @@ end ...@@ -197,11 +197,10 @@ end
1. SyntacticallyUnreachable is disabled (otherwise it already checks them); 1. SyntacticallyUnreachable is disabled (otherwise it already checks them);
2. No warnings were emitted for the function (otherwise it may be redundant). *) 2. No warnings were emitted for the function (otherwise it may be redundant). *)
let check_unreachable_returns kf = let check_unreachable_returns kf =
let st = Db.Value.get_initial_state kf in if Eva.Results.is_called kf then begin
if Db.Value.is_reachable st then begin
try try
let ret_stmt = Kernel_function.find_return kf in let ret_stmt = Kernel_function.find_return kf in
if not (Db.Value.is_reachable_stmt ret_stmt) then if not (Eva.Results.is_reachable ret_stmt) then
warn_unreachable_statement ret_stmt warn_unreachable_statement ret_stmt
with with
| Kernel_function.No_Statement -> (* should never happen *) | Kernel_function.No_Statement -> (* should never happen *)
...@@ -221,25 +220,24 @@ let check_unreachable_statements kf ~to_ignore ~dead_code ~warned_kfs = ...@@ -221,25 +220,24 @@ let check_unreachable_statements kf ~to_ignore ~dead_code ~warned_kfs =
considered as always terminating" considered as always terminating"
Kernel_function.pretty kf Kernel_function.pretty kf
else else
let st = Db.Value.get_initial_state kf in if Eva.Results.is_called kf then begin
if Db.Value.is_reachable st then begin try
try let vis = new unreachable_stmt_visitor kf to_ignore in
let vis = new unreachable_stmt_visitor kf to_ignore in ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
if dead_code then begin
(* compute syntactically unreachable statements *)
let vis = new dead_cc_collector kf in
ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf); ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf);
if dead_code then begin let cc_heads = List.map List.hd vis#get in
(* compute syntactically unreachable statements *) Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads)
let vis = new dead_cc_collector kf in end
ignore (Visitor.visitFramacKf (vis :> Visitor.frama_c_visitor) kf); else if not (Kernel_function.Set.mem kf warned_kfs) then
let cc_heads = List.map List.hd vis#get in check_unreachable_returns kf
Stmt.Hptset.iter (fun h -> warn_dead_code h) (Stmt.Hptset.of_list cc_heads) with
end | Kernel_function.No_Statement -> (* should never happen *)
else if not (Kernel_function.Set.mem kf warned_kfs) then Self.error "function %a has no return statement, skipping"
check_unreachable_returns kf Kernel_function.pretty kf;
with end
| Kernel_function.No_Statement -> (* should never happen *)
Self.error "function %a has no return statement, skipping"
Kernel_function.pretty kf;
end
(* To avoid redundant warnings, calls to possibly non-terminating functions (* To avoid redundant warnings, calls to possibly non-terminating functions
are ignored if: are ignored if:
...@@ -281,14 +279,6 @@ class stmt_collector = object ...@@ -281,14 +279,6 @@ class stmt_collector = object
method get_instr_stmts = List.rev !instr_stmts method get_instr_stmts = List.rev !instr_stmts
end end
let get_callstack_state ~after stmt cs =
match Db.Value.get_stmt_state_callstack ~after stmt with
| None -> None (* unreachable stmt *)
| Some table ->
try
Some (Value_types.Callstack.Hashtbl.find table cs)
with Not_found -> None
(* collects the list of non-terminating instructions *) (* collects the list of non-terminating instructions *)
let collect_nonterminating_statements fd nonterm_stacks = let collect_nonterminating_statements fd nonterm_stacks =
let vis = new stmt_collector in let vis = new stmt_collector in
...@@ -309,40 +299,23 @@ let collect_nonterminating_statements fd nonterm_stacks = ...@@ -309,40 +299,23 @@ let collect_nonterminating_statements fd nonterm_stacks =
| _ -> | _ ->
let source = fst (Stmt.loc stmt) in let source = fst (Stmt.loc stmt) in
Self.debug ~source "processing stmt:@ %a" Printer.pp_stmt stmt; Self.debug ~source "processing stmt:@ %a" Printer.pp_stmt stmt;
match Db.Value.get_stmt_state_callstack ~after:false stmt with let process_callstack cs _ =
| None -> () (* unreachable stmt *) if Eva.Results.(after stmt |> in_callstack cs |> is_empty) then
| Some before_table -> add_stack stmt cs
Value_types.Callstack.Hashtbl.iter else if match stmt.skind with Loop _ -> true | _ -> false then begin
(fun cs before_state -> (* special treatment for loops: even if their after state
try is reachable, we must check that at least one outgoing
match Db.Value.get_stmt_state_callstack ~after:true stmt with edge is reachable *)
| None -> (* no after table => non-terminating statement *) let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
add_stack stmt cs let all_out_edges_unreachable =
| Some after_table -> List.for_all (fun (_, out_stmt) ->
let after_state = Eva.Results.(before out_stmt |> in_callstack cs |> is_empty)
Value_types.Callstack.Hashtbl.find after_table cs ) out_edges
in in
if Cvalue.Model.is_reachable before_state then if all_out_edges_unreachable then add_stack stmt cs
if not (Cvalue.Model.is_reachable after_state) then add_stack stmt cs end
else if match stmt.skind with Loop _ -> true | _ -> false then begin in
(* special treatment for loops: even if their after state Eva.Results.(before stmt |> iter_callstacks process_callstack)
is reachable, we must check that at least one outgoing
edge is reachable *)
let out_edges = Stmts_graph.get_all_stmt_out_edges stmt in
let all_out_edges_unreachable =
List.for_all (fun (_, out_stmt) ->
match get_callstack_state ~after:false out_stmt cs with
| None -> true
| Some state -> not (Cvalue.Model.is_reachable state)
) out_edges
in
if all_out_edges_unreachable then add_stack stmt cs
end
with
| Not_found ->
(* in this callstack, the statement is non-terminating *)
add_stack stmt cs
) before_table
) vis#get_instr_stmts; ) vis#get_instr_stmts;
!new_nonterm_stmts !new_nonterm_stmts
...@@ -364,7 +337,7 @@ let cmp_callstacks cs1 cs2 = ...@@ -364,7 +337,7 @@ let cmp_callstacks cs1 cs2 =
let run () = let run () =
if not (Ast.is_computed ()) then if not (Ast.is_computed ()) then
Self.abort "nonterm requires a computed AST"; Self.abort "nonterm requires a computed AST";
if not (Db.Value.is_computed ()) then if not (Eva.Analysis.is_computed ()) then
Self.abort "nonterm requires a computed value analysis"; Self.abort "nonterm requires a computed value analysis";
Self.debug "Starting analysis..."; Self.debug "Starting analysis...";
let file = Ast.get () in let file = Ast.get () in
...@@ -398,7 +371,7 @@ let run () = ...@@ -398,7 +371,7 @@ let run () =
Self.feedback ~level:2 "Analysis done." Self.feedback ~level:2 "Analysis done."
;; ;;
let run_once, _ = State_builder.apply_once "Nonterm.run" [Db.Value.self] run let run_once, _ = State_builder.apply_once "Nonterm.run" [Eva.Analysis.self] run
let main () = let main () =
if Enabled.get () then run_once () if Enabled.get () then run_once ()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment