@ -39,7 +39,7 @@ let read_dirs_to_analyze () =
let dirs_to_analyze =
lazy ( read_dirs_to_analyze () )
type analyze_ondemand = Procname . t -> unit
type analyze_ondemand = Cfg. Procdesc . t -> unit
type get_cfg = Procname . t -> Cfg . cfg option
@ -62,21 +62,24 @@ let unset_callbacks () =
let nesting = ref 0
let should_be_analyzed proc_attributes proc_name =
let currently_analyzed () =
Specs . summary_exists proc_name &&
Specs . is_active proc_name in
let already_analyzed () =
match Specs . get_summary proc_name with
| Some summary ->
Specs . get_timestamp summary > 0
| None ->
false in
proc_attributes . ProcAttributes . is_defined && (* we have the implementation *)
not ( currently_analyzed () ) && (* avoid infinite loops *)
not ( already_analyzed () ) (* avoid re-analysis of the same procedure *)
let procedure_should_be_analyzed proc_name =
match AttributesTable . load_attributes proc_name with
| Some proc_attributes ->
let currently_analyzed =
Specs . summary_exists proc_name &&
Specs . is_active proc_name in
let already_analyzed = match Specs . get_summary proc_name with
| Some summary ->
Specs . get_timestamp summary > 0
| None ->
false in
proc_attributes . ProcAttributes . is_defined && (* we have the implementation *)
not currently_analyzed && (* avoid infinite loops *)
not already_analyzed (* avoid re-analysis of the same procedure *)
should_be_analyzed proc_attributes proc_name
| None ->
false
@ -117,86 +120,102 @@ let restore_global_state st =
State . restore_state st . symexec_state ;
Timeout . resume_previous_timeout ()
(* * do_analysis curr_pdesc proc_name
performs an on - demand analysis of proc_name
triggered during the analysis of curr_pname . * )
let do_analysis ~ propagate_exceptions curr_pdesc callee_pname =
let run_proc_analysis ~ propagate_exceptions analyze_proc curr_pdesc callee_pdesc =
let curr_pname = Cfg . Procdesc . get_proc_name curr_pdesc in
let callee_pname = Cfg . Procdesc . get_proc_name callee_pdesc in
(* * Dot means start of a procedure *)
L . log_progress_procedure () ;
if trace () then L . stderr " [%d] run_proc_analysis %a -> %a@. "
! nesting
Procname . pp curr_pname
Procname . pp callee_pname ;
let preprocess () =
incr nesting ;
let attributes_opt =
Specs . proc_resolve_attributes callee_pname in
Option . may
( fun attribute ->
DB . current_source := attribute . ProcAttributes . loc . Location . file ;
let attribute_pname = attribute . ProcAttributes . proc_name in
if not ( Procname . equal callee_pname attribute_pname ) then
failwith ( " ERROR: " ^ ( Procname . to_string callee_pname )
^ " not equal to " ^ ( Procname . to_string attribute_pname ) ) )
attributes_opt ;
let call_graph =
let cg = Cg . create () in
Cg . add_defined_node cg callee_pname ;
cg in
Specs . reset_summary call_graph callee_pname attributes_opt ;
Specs . set_status callee_pname Specs . ACTIVE in
let postprocess () =
decr nesting ;
let summary = Specs . get_summary_unsafe " ondemand " callee_pname in
let summary' =
{ summary with
Specs . status = Specs . INACTIVE ;
timestamp = summary . Specs . timestamp + 1 } in
Specs . add_summary callee_pname summary' ;
Checkers . ST . store_summary callee_pname ;
Printer . proc_write_log false callee_pdesc in
let log_error_and_continue exn kind =
Reporting . log_error callee_pname exn ;
let prev_summary = Specs . get_summary_unsafe " Ondemand.do_analysis " callee_pname in
let timestamp = max 1 ( prev_summary . Specs . timestamp ) in
let stats = { prev_summary . Specs . stats with Specs . stats_failure = Some kind } in
let payload =
{ prev_summary . Specs . payload with Specs . preposts = Some [] ; } in
let new_summary =
{ prev_summary with Specs . stats ; payload ; timestamp ; } in
Specs . add_summary callee_pname new_summary in
let old_state = save_global_state () in
preprocess () ;
try
analyze_proc callee_pdesc ;
postprocess () ;
restore_global_state old_state ;
with exn ->
L . stderr " @.ONDEMAND EXCEPTION %a %s@.@.CALL STACK@.%s@.BACK TRACE@.%s@. "
Procname . pp callee_pname
( Printexc . to_string exn )
( Printexc . raw_backtrace_to_string ( Printexc . get_callstack 1000 ) )
( Printexc . get_backtrace () ) ;
restore_global_state old_state ;
if propagate_exceptions
then
raise exn
else
match exn with
| Analysis_failure_exe kind ->
(* in production mode, log the timeout/crash and continue with the summary we had before
the failure occurred * )
log_error_and_continue exn kind
| _ ->
(* this happens with assert false or some other unrecognized exception *)
log_error_and_continue exn ( FKcrash ( Printexc . to_string exn ) )
let analyze_proc_desc ~ propagate_exceptions curr_pdesc callee_pdesc =
let callee_pname = Cfg . Procdesc . get_proc_name callee_pdesc in
let proc_attributes = Cfg . Procdesc . get_attributes callee_pdesc in
match ! callbacks_ref with
| Some callbacks
when should_be_analyzed proc_attributes callee_pname ->
run_proc_analysis
~ propagate_exceptions callbacks . analyze_ondemand curr_pdesc callee_pdesc
| _ -> ()
let really_do_analysis callee_pdesc analyze_proc =
(* * Dot means start of a procedure *)
L . log_progress_procedure () ;
if trace () then L . stderr " [%d] really_do_analysis %a -> %a@. "
! nesting
Procname . pp curr_pname
Procname . pp callee_pname ;
let preprocess () =
incr nesting ;
let attributes_opt =
Specs . proc_resolve_attributes callee_pname in
Option . may
( fun attribute ->
DB . current_source := attribute . ProcAttributes . loc . Location . file ;
let attribute_pname = attribute . ProcAttributes . proc_name in
if not ( Procname . equal callee_pname attribute_pname ) then
failwith ( " ERROR: " ^ ( Procname . to_string callee_pname )
^ " not equal to " ^ ( Procname . to_string attribute_pname ) ) )
attributes_opt ;
let call_graph =
let cg = Cg . create () in
Cg . add_defined_node cg callee_pname ;
cg in
Specs . reset_summary call_graph callee_pname attributes_opt ;
Specs . set_status callee_pname Specs . ACTIVE in
let postprocess () =
decr nesting ;
let summary = Specs . get_summary_unsafe " ondemand " callee_pname in
let summary' =
{ summary with
Specs . status = Specs . INACTIVE ;
timestamp = summary . Specs . timestamp + 1 } in
Specs . add_summary callee_pname summary' ;
Checkers . ST . store_summary callee_pname ;
Printer . proc_write_log false callee_pdesc in
let log_error_and_continue exn kind =
Reporting . log_error callee_pname exn ;
let prev_summary = Specs . get_summary_unsafe " Ondemand.do_analysis " callee_pname in
let timestamp = max 1 ( prev_summary . Specs . timestamp ) in
let stats = { prev_summary . Specs . stats with Specs . stats_failure = Some kind } in
let payload =
{ prev_summary . Specs . payload with Specs . preposts = Some [] ; } in
let new_summary =
{ prev_summary with Specs . stats ; payload ; timestamp ; } in
Specs . add_summary callee_pname new_summary in
let old_state = save_global_state () in
preprocess () ;
try
analyze_proc callee_pname ;
postprocess () ;
restore_global_state old_state ;
with exn ->
L . stderr " @.ONDEMAND EXCEPTION %a %s@.@.CALL STACK@.%s@.BACK TRACE@.%s@. "
Procname . pp callee_pname
( Printexc . to_string exn )
( Printexc . raw_backtrace_to_string ( Printexc . get_callstack 1000 ) )
( Printexc . get_backtrace () ) ;
restore_global_state old_state ;
if propagate_exceptions
then
raise exn
else
match exn with
| Analysis_failure_exe kind ->
(* in production mode, log the timeout/crash and continue with the summary we had before
the failure occurred * )
log_error_and_continue exn kind
| _ ->
(* this happens with assert false or some other unrecognized exception *)
log_error_and_continue exn ( FKcrash ( Printexc . to_string exn ) ) in
(* * analyze_proc_name curr_pdesc proc_name
performs an on - demand analysis of proc_name
triggered during the analysis of curr_pname . * )
let analyze_proc_name ~ propagate_exceptions curr_pdesc callee_pname =
match ! callbacks_ref with
| Some callbacks
@ -204,7 +223,7 @@ let do_analysis ~propagate_exceptions curr_pdesc callee_pname =
begin
match callbacks . get_proc_desc callee_pname with
| Some callee_pdesc ->
really_do_analysis callee_pdesc callbacks . analyze_ondemand
analyze_proc_desc ~ propagate_exceptions curr_pdesc callee_pdesc
| None ->
()
end