Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
e4ba69e0
Commit
e4ba69e0
authored
3 years ago
by
Valentin Perrelle
Committed by
David Bühler
3 years ago
Browse files
Options
Downloads
Patches
Plain Diff
[Nonterm] Use the new Eva API
parent
2faaf0d7
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/plugins/nonterm/nonterm_run.ml
+39
-66
39 additions, 66 deletions
src/plugins/nonterm/nonterm_run.ml
with
39 additions
and
66 deletions
src/plugins/nonterm/nonterm_run.ml
+
39
−
66
View file @
e4ba69e0
...
@@ -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
()
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment