@ -344,7 +344,7 @@ let check_inherently_dangerous_function caller_pname callee_pname =
Exceptions . Inherently_dangerous_function
Exceptions . Inherently_dangerous_function
( Localise . desc_inherently_dangerous_function callee_pname )
( Localise . desc_inherently_dangerous_function callee_pname )
in
in
Biabduction Reporting. log_issue_deprecated_using_state Exceptions . Warning caller_pname exn
Summary Reporting. log_issue_deprecated_using_state Exceptions . Warning caller_pname exn
let reason_to_skip ~ callee_desc : string option =
let reason_to_skip ~ callee_desc : string option =
@ -359,10 +359,10 @@ let reason_to_skip ~callee_desc : string option =
else None
else None
in
in
match callee_desc with
match callee_desc with
| ` Summary callee_summary ->
| ` Summary ( callee_pdesc , callee_summary ) ->
let attr_reason = Summary. get_attributes callee_summary | > reason_from_attributes in
let attr_reason = Procdesc. get_attributes callee_pdesc | > reason_from_attributes in
if Option . is_some attr_reason then attr_reason
if Option . is_some attr_reason then attr_reason
else if List . is_empty ( Tabulation. get_specs_from_payload callee_summary ) then
else if List . is_empty ( BiabductionSummary. get_specs callee_summary ) then
Some " empty list of specs "
Some " empty list of specs "
else (* we are not skipping *) None
else (* we are not skipping *) None
| ` ProcDesc procdesc ->
| ` ProcDesc procdesc ->
@ -409,7 +409,7 @@ let check_arith_norm_exp tenv pname exp prop =
( AnalysisState . get_loc_exn () )
( AnalysisState . get_loc_exn () )
in
in
let exn = Exceptions . Divide_by_zero ( desc , _ _ POS__ ) in
let exn = Exceptions . Divide_by_zero ( desc , _ _ POS__ ) in
Biabduction Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn ;
Summary Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn ;
( Prop . exp_normalize_prop tenv prop exp , prop' )
( Prop . exp_normalize_prop tenv prop exp , prop' )
| Some ( Attribute . UminusUnsigned ( e , typ ) ) , prop' ->
| Some ( Attribute . UminusUnsigned ( e , typ ) ) , prop' ->
let desc =
let desc =
@ -417,7 +417,7 @@ let check_arith_norm_exp tenv pname exp prop =
( AnalysisState . get_node_exn () ) ( AnalysisState . get_loc_exn () )
( AnalysisState . get_node_exn () ) ( AnalysisState . get_loc_exn () )
in
in
let exn = Exceptions . Unary_minus_applied_to_unsigned_expression ( desc , _ _ POS__ ) in
let exn = Exceptions . Unary_minus_applied_to_unsigned_expression ( desc , _ _ POS__ ) in
Biabduction Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn ;
Summary Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn ;
( Prop . exp_normalize_prop tenv prop exp , prop' )
( Prop . exp_normalize_prop tenv prop exp , prop' )
| None , prop' ->
| None , prop' ->
( Prop . exp_normalize_prop tenv prop exp , prop' )
( Prop . exp_normalize_prop tenv prop exp , prop' )
@ -475,7 +475,7 @@ let check_already_dereferenced tenv pname cond prop =
( AnalysisState . get_node_exn () ) n ( AnalysisState . get_loc_exn () )
( AnalysisState . get_node_exn () ) n ( AnalysisState . get_loc_exn () )
in
in
let exn = Exceptions . Null_test_after_dereference ( desc , _ _ POS__ ) in
let exn = Exceptions . Null_test_after_dereference ( desc , _ _ POS__ ) in
Biabduction Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn
Summary Reporting. log_issue_deprecated_using_state Exceptions . Warning pname exn
| None ->
| None ->
()
()
@ -684,29 +684,26 @@ let resolve_args prop args =
type resolve_and_analyze_result =
type resolve_and_analyze_result =
{ resolved_pname : Procname . t
{ resolved_pname : Procname . t
; resolved_procdesc_opt : Procdesc . t option
; resolved_procdesc_opt : Procdesc . t option
; resolved_summary_opt : Summary. t option }
; resolved_summary_opt : ( Procdesc. t * Biabduction Summary. t ) option }
(* * Resolve the procedure name and run the analysis of the resolved procedure if not already
(* * Resolve the procedure name and run the analysis of the resolved procedure if not already
analyzed * )
analyzed * )
let resolve_and_analyze tenv ~ caller_summary ? ( has_clang_model = false ) prop args callee_proc_name
let resolve_and_analyze
call_flags : resolve_and_analyze_result =
{ InterproceduralAnalysis . analyze_dependency ; analyze_pdesc_dependency ; proc_desc ; tenv }
? ( has_clang_model = false ) prop args callee_proc_name call_flags : resolve_and_analyze_result =
(* TODO ( #15748878 ) : Fix conflict with method overloading by encoding in the procedure name
(* TODO ( #15748878 ) : Fix conflict with method overloading by encoding in the procedure name
whether the method is defined or generated by the specialization * )
whether the method is defined or generated by the specialization * )
let analyze_ondemand resolved_pname : Procdesc . t option * Summary . t option =
let analyze_ondemand resolved_pname =
if Procname . equal resolved_pname callee_proc_name then
if Procname . equal resolved_pname callee_proc_name then
( Ondemand . get_proc_desc callee_proc_name
( AnalysisCallbacks . get_proc_desc callee_proc_name , analyze_dependency callee_proc_name )
, Ondemand . analyze_proc_name ~ caller_summary callee_proc_name )
else
else
(* Create the type specialized procedure description and analyze it directly *)
(* Create the type specialized procedure description and analyze it directly *)
let analyze specialized_pdesc =
Ondemand . analyze_proc_desc ~ caller_summary specialized_pdesc
in
let resolved_proc_desc_option =
let resolved_proc_desc_option =
match Ondemand . get_proc_desc resolved_pname with
match AnalysisCallbacks . get_proc_desc resolved_pname with
| Some _ as resolved_proc_desc ->
| Some _ as resolved_proc_desc ->
resolved_proc_desc
resolved_proc_desc
| None ->
| None ->
let procdesc_opt = Ondemand . get_proc_desc callee_proc_name in
let procdesc_opt = AnalysisCallbacks . get_proc_desc callee_proc_name in
Option . map procdesc_opt ~ f : ( fun callee_proc_desc ->
Option . map procdesc_opt ~ f : ( fun callee_proc_desc ->
(* It is possible that the types of the arguments are not as precise as the type of
(* It is possible that the types of the arguments are not as precise as the type of
the objects in the heap , so we should update them to get the best results . * )
the objects in the heap , so we should update them to get the best results . * )
@ -714,12 +711,12 @@ let resolve_and_analyze tenv ~caller_summary ?(has_clang_model = false) prop arg
SpecializeProcdesc . with_formals_types ~ has_clang_model callee_proc_desc
SpecializeProcdesc . with_formals_types ~ has_clang_model callee_proc_desc
resolved_pname resolved_args )
resolved_pname resolved_args )
in
in
( resolved_proc_desc_option , Option . bind resolved_proc_desc_option ~ f : analyze )
( resolved_proc_desc_option
, Option . bind resolved_proc_desc_option ~ f : ( fun pdesc ->
analyze_pdesc_dependency pdesc | > Option . map ~ f : ( fun summary -> ( pdesc , summary ) ) ) )
in
in
let resolved_pname =
let resolved_pname =
resolve_pname
resolve_pname ~ caller_pdesc : proc_desc tenv prop args callee_proc_name call_flags
~ caller_pdesc : ( Summary . get_proc_desc caller_summary )
tenv prop args callee_proc_name call_flags
in
in
let resolved_procdesc_opt , resolved_summary_opt = analyze_ondemand resolved_pname in
let resolved_procdesc_opt , resolved_summary_opt = analyze_ondemand resolved_pname in
{ resolved_pname ; resolved_procdesc_opt ; resolved_summary_opt }
{ resolved_pname ; resolved_procdesc_opt ; resolved_summary_opt }
@ -858,9 +855,7 @@ let handle_objc_instance_method_call_or_skip pdesc tenv actual_pars path callee_
(* This method handles ObjC instance method calls, in particular the fact that calling a method *)
(* This method handles ObjC instance method calls, in particular the fact that calling a method *)
(* with nil returns nil. The exec_call function is either standard call execution or execution *)
(* with nil returns nil. The exec_call function is either standard call execution or execution *)
(* of ObjC getters and setters using a builtin. *)
(* of ObjC getters and setters using a builtin. *)
let handle_objc_instance_method_call actual_pars actual_params pre tenv ret_id pdesc callee_pname
let handle_objc_instance_method_call actual_pars pre tenv ret_id pdesc callee_pname path res =
loc path exec_call =
let res () = exec_call tenv ret_id pdesc callee_pname loc actual_params pre path in
handle_objc_instance_method_call_or_skip pdesc tenv actual_pars path callee_pname pre ret_id res
handle_objc_instance_method_call_or_skip pdesc tenv actual_pars path callee_pname pre ret_id res
@ -1078,13 +1073,13 @@ let execute_store ?(report_deref_errors = true) pname pdesc tenv lhs_exp typ rhs
let is_variadic_procname callee_pname =
let is_variadic_procname callee_pname =
Option . value_map
Option . value_map
( Ondemand . get_proc_desc callee_pname )
( AnalysisCallbacks . get_proc_desc callee_pname )
~ f : ( fun proc_desc -> ( Procdesc . get_attributes proc_desc ) . ProcAttributes . is_variadic )
~ f : ( fun proc_desc -> ( Procdesc . get_attributes proc_desc ) . ProcAttributes . is_variadic )
~ default : false
~ default : false
let resolve_and_analyze_no_dynamic_dispatch current_summary tenv prop_r n_actual_params callee_pname
let resolve_and_analyze_no_dynamic_dispatch { InterproceduralAnalysis . analyze_dependency ; tenv }
call_flags =
prop_r n_actual_params callee_pname call_flags =
let resolved_pname =
let resolved_pname =
match resolve_virtual_pname tenv prop_r n_actual_params callee_pname call_flags with
match resolve_virtual_pname tenv prop_r n_actual_params callee_pname call_flags with
| resolved_pname :: _ ->
| resolved_pname :: _ ->
@ -1092,15 +1087,13 @@ let resolve_and_analyze_no_dynamic_dispatch current_summary tenv prop_r n_actual
| [] ->
| [] ->
callee_pname
callee_pname
in
in
let resolved_summary_opt =
let resolved_summary_opt = analyze_dependency resolved_pname in
Ondemand . analyze_proc_name ~ caller_summary : current_summary resolved_pname
in
{ resolved_pname
{ resolved_pname
; resolved_procdesc_opt = Ondemand . get_proc_desc resolved_pname
; resolved_procdesc_opt = AnalysisCallbacks . get_proc_desc resolved_pname
; resolved_summary_opt }
; resolved_summary_opt }
let resolve_and_analyze_clang current_summary tenv prop_r n_actual_params callee_pname call_flags =
let resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname call_flags =
if
if
Config . dynamic_dispatch
Config . dynamic_dispatch
&& ( not ( is_variadic_procname callee_pname ) )
&& ( not ( is_variadic_procname callee_pname ) )
@ -1111,30 +1104,30 @@ let resolve_and_analyze_clang current_summary tenv prop_r n_actual_params callee
try
try
let has_clang_model = BiabductionModels . mem callee_pname in
let has_clang_model = BiabductionModels . mem callee_pname in
let resolve_and_analyze_result =
let resolve_and_analyze_result =
resolve_and_analyze tenv ~ caller_summary : current_summary ~ has_clang_model prop_r
resolve_and_analyze analysis_data ~ has_clang_model prop_r n_actual_params callee_pname
n_actual_params callee_pname call_flags
call_flags
in
in
(* It could be useful to specialize a model, but also it could cause a failure,
(* It could be useful to specialize a model, but also it could cause a failure,
because we don't have the correct fields in the tenv .
because we don't have the correct fields in the tenv .
In that case , default to the non - specialized spec for the model . * )
In that case , default to the non - specialized spec for the model . * )
let clang_model_specialized_failure =
let clang_model_specialized_failure =
match resolve_and_analyze_result . resolved_summary_opt with
match resolve_and_analyze_result . resolved_summary_opt with
| Some summary when has_clang_model ->
| Some ( _ , summary ) when has_clang_model ->
List . is_empty ( Tabulation. get_specs_from_payload summary )
List . is_empty ( BiabductionSummary. get_specs summary )
| None ->
| None ->
true
true
| _ ->
| _ ->
false
false
in
in
if clang_model_specialized_failure then
if clang_model_specialized_failure then
resolve_and_analyze_no_dynamic_dispatch current_summary tenv prop_r n_actual_params
resolve_and_analyze_no_dynamic_dispatch analysis_data prop_r n_actual_params callee_pname
call ee_pname call _flags
call _flags
else resolve_and_analyze_result
else resolve_and_analyze_result
with SpecializeProcdesc . UnmatchedParameters ->
with SpecializeProcdesc . UnmatchedParameters ->
resolve_and_analyze_no_dynamic_dispatch current_summary tenv prop_r n_actual_params
resolve_and_analyze_no_dynamic_dispatch analysis_data prop_r n_actual_params callee_pname
call ee_pname call _flags
call _flags
else
else
resolve_and_analyze_no_dynamic_dispatch current_summary tenv prop_r n_actual_params callee_pname
resolve_and_analyze_no_dynamic_dispatch analysis_data prop_r n_actual_params callee_pname
call_flags
call_flags
@ -1171,9 +1164,9 @@ let declare_locals_and_ret tenv pdesc (prop_ : Prop.normal Prop.t) =
(* * Execute [instr] with a symbolic heap [prop]. *)
(* * Execute [instr] with a symbolic heap [prop]. *)
let rec sym_exec exe_env tenv current_summary instr_ ( prop_ : Prop . normal Prop . t ) path :
let rec sym_exec
( Prop . normal Prop . t * Paths . Path . t ) list =
( { InterproceduralAnalysis . proc_desc = current_pdesc ; analyze_dependency ; tenv } as analysis_data )
let current_pdesc = Summary . get_proc_desc current_summary in
instr_ ( prop_ : Prop . normal Prop . t ) path : ( Prop . normal Prop . t * Paths . Path . t ) list =
let current_pname = Procdesc . get_proc_name current_pdesc in
let current_pname = Procdesc . get_proc_name current_pdesc in
AnalysisState . set_instr instr_ ;
AnalysisState . set_instr instr_ ;
(* mark instruction last seen *)
(* mark instruction last seen *)
@ -1207,20 +1200,17 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
ret_id_typ ret_typ actual_args =
ret_id_typ ret_typ actual_args =
let skip_res () =
let skip_res () =
let exn = Exceptions . Skip_function ( Localise . desc_skip_function callee_pname ) in
let exn = Exceptions . Skip_function ( Localise . desc_skip_function callee_pname ) in
Biabduction Reporting. log_issue_deprecated_using_state Exceptions . Info current_pname exn ;
Summary Reporting. log_issue_deprecated_using_state Exceptions . Info current_pname exn ;
L . d_printfln " Skipping function '%a': %s " Procname . pp callee_pname reason ;
L . d_printfln " Skipping function '%a': %s " Procname . pp callee_pname reason ;
unknown_or_scan_call ~ is_scan : false ~ reason ret_typ ret_annots
unknown_or_scan_call ~ is_scan : false ~ reason ret_typ ret_annots
Builtin .
{ Builtin . instr
{ summary = current_summary
; prop_ = prop
; instr
; path
; tenv
; ret_id_typ
; prop_ = prop
; args = actual_args
; path
; proc_name = callee_pname
; ret_id_typ
; loc
; args = actual_args
; analysis_data }
; proc_name = callee_pname
; loc
; exe_env }
in
in
if is_objc_instance_method then
if is_objc_instance_method then
handle_objc_instance_method_call_or_skip current_pdesc tenv actual_args path callee_pname prop
handle_objc_instance_method_call_or_skip current_pdesc tenv actual_args path callee_pname prop
@ -1228,16 +1218,7 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
else skip_res ()
else skip_res ()
in
in
let call_args prop_ proc_name args ret_id_typ loc =
let call_args prop_ proc_name args ret_id_typ loc =
{ Builtin . summary = current_summary
{ Builtin . instr ; prop_ ; path ; ret_id_typ ; args ; proc_name ; loc ; analysis_data }
; instr
; tenv
; prop_
; path
; ret_id_typ
; args
; proc_name
; loc
; exe_env }
in
in
match instr with
match instr with
| Sil . Load { id ; e = rhs_exp ; root_typ = typ ; loc } ->
| Sil . Load { id ; e = rhs_exp ; root_typ = typ ; loc } ->
@ -1270,8 +1251,7 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
let exn =
let exn =
Exceptions . Condition_always_true_false ( desc , not ( IntLit . iszero i ) , _ _ POS__ )
Exceptions . Condition_always_true_false ( desc , not ( IntLit . iszero i ) , _ _ POS__ )
in
in
BiabductionReporting . log_issue_deprecated_using_state Exceptions . Warning current_pname
SummaryReporting . log_issue_deprecated_using_state Exceptions . Warning current_pname exn
exn
| _ ->
| _ ->
()
()
in
in
@ -1294,8 +1274,7 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
norm_args
norm_args
in
in
let resolve_and_analyze_result =
let resolve_and_analyze_result =
resolve_and_analyze tenv ~ caller_summary : current_summary norm_prop norm_args
resolve_and_analyze analysis_data norm_prop norm_args callee_pname call_flags
callee_pname call_flags
in
in
let resolved_pname = resolve_and_analyze_result . resolved_pname in
let resolved_pname = resolve_and_analyze_result . resolved_pname in
match resolve_and_analyze_result . resolved_summary_opt with
match resolve_and_analyze_result . resolved_summary_opt with
@ -1303,13 +1282,12 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
let ret_typ = Procname . Java . get_return_typ callee_pname_java in
let ret_typ = Procname . Java . get_return_typ callee_pname_java in
let ret_annots = load_ret_annots callee_pname in
let ret_annots = load_ret_annots callee_pname in
exec_skip_call ~ reason : " unknown method " resolved_pname ret_annots ret_typ
exec_skip_call ~ reason : " unknown method " resolved_pname ret_annots ret_typ
| Some resolved_summary -> (
| Some ( ( callee_proc_desc , _ ) as resolved_summary ) -> (
match reason_to_skip ~ callee_desc : ( ` Summary resolved_summary ) with
match reason_to_skip ~ callee_desc : ( ` Summary resolved_summary ) with
| None ->
| None ->
proc_call exe_env resolved_summary
proc_call resolved_summary ( call_args prop_ callee_pname norm_args ret_id_typ loc )
( call_args prop_ callee_pname norm_args ret_id_typ loc )
| Some reason ->
| Some reason ->
let proc_attrs = Summary. get_attributes resolved_summary in
let proc_attrs = Procdesc. get_attributes callee_proc_desc in
let ret_annots = proc_attrs . ProcAttributes . method_annotation . return in
let ret_annots = proc_attrs . ProcAttributes . method_annotation . return in
exec_skip_call ~ reason resolved_pname ret_annots proc_attrs . ProcAttributes . ret_type
exec_skip_call ~ reason resolved_pname ret_annots proc_attrs . ProcAttributes . ret_type
) )
) )
@ -1324,18 +1302,18 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
skip_call ~ reason norm_prop path pname ret_annots loc ret_id_typ ret_type
skip_call ~ reason norm_prop path pname ret_annots loc ret_id_typ ret_type
url_handled_args
url_handled_args
in
in
match Ondemand . analyze_proc_name ~ caller_summary : current_summar y pname with
match analyze_dependenc y pname with
| None ->
| None ->
let ret_typ = Procname . Java . get_return_typ callee_pname_java in
let ret_typ = Procname . Java . get_return_typ callee_pname_java in
let ret_annots = load_ret_annots callee_pname in
let ret_annots = load_ret_annots callee_pname in
exec_skip_call ~ reason : " unknown method " ret_annots ret_typ
exec_skip_call ~ reason : " unknown method " ret_annots ret_typ
| Some callee_summary -> (
| Some ( ( callee_proc_desc , _ ) as callee_summary ) -> (
match reason_to_skip ~ callee_desc : ( ` Summary callee_summary ) with
match reason_to_skip ~ callee_desc : ( ` Summary callee_summary ) with
| None ->
| None ->
let handled_args = call_args norm_prop pname url_handled_args ret_id_typ loc in
let handled_args = call_args norm_prop pname url_handled_args ret_id_typ loc in
proc_call exe_env callee_summary handled_args
proc_call callee_summary handled_args
| Some reason ->
| Some reason ->
let proc_attrs = Summary. get_attributes callee_summary in
let proc_attrs = Procdesc. get_attributes callee_proc_desc in
let ret_annots = proc_attrs . ProcAttributes . method_annotation . return in
let ret_annots = proc_attrs . ProcAttributes . method_annotation . return in
exec_skip_call ~ reason ret_annots proc_attrs . ProcAttributes . ret_type )
exec_skip_call ~ reason ret_annots proc_attrs . ProcAttributes . ret_type )
in
in
@ -1346,8 +1324,8 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
(* method with block parameters *)
(* method with block parameters *)
let with_block_parameters_summary_opt =
let with_block_parameters_summary_opt =
if call_flags . CallFlags . cf_with_block_parameters then
if call_flags . CallFlags . cf_with_block_parameters then
SymExecBlocks . resolve_method_with_block_args_and_analyze
SymExecBlocks . resolve_method_with_block_args_and_analyze analysis_data callee_pname
~ caller_summary : current_summary callee_pname actual_params
actual_params
else None
else None
in
in
match with_block_parameters_summary_opt with
match with_block_parameters_summary_opt with
@ -1356,12 +1334,12 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
normalize_params tenv current_pname prop_r extended_actual_params
normalize_params tenv current_pname prop_r extended_actual_params
in
in
Logging . d_strln " Calling method specialized with blocks... " ;
Logging . d_strln " Calling method specialized with blocks... " ;
proc_call exe_env resolved_summary
proc_call resolved_summary
( call_args prop_r callee_pname n_extended_actual_params ret_id_typ loc )
( call_args prop_r callee_pname n_extended_actual_params ret_id_typ loc )
| None ->
| None ->
(* Generic fun call with known name *)
(* Generic fun call with known name *)
let resolve_and_analyze_result =
let resolve_and_analyze_result =
resolve_and_analyze_clang current_summary tenv prop_r n_actual_params callee_pname
resolve_and_analyze_clang analysis_data prop_r n_actual_params callee_pname
call_flags
call_flags
in
in
let resolved_pname = resolve_and_analyze_result . resolved_pname in
let resolved_pname = resolve_and_analyze_result . resolved_pname in
@ -1389,8 +1367,9 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
| Some reason -> (
| Some reason -> (
let ret_annots =
let ret_annots =
match resolved_summary_opt with
match resolved_summary_opt with
| Some summ ->
| Some ( proc_desc , _ ) ->
( Summary . get_attributes summ ) . ProcAttributes . method_annotation . return
( Procdesc . get_attributes proc_desc ) . ProcAttributes . method_annotation
. return
| None ->
| None ->
load_ret_annots resolved_pname
load_ret_annots resolved_pname
in
in
@ -1404,13 +1383,15 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
match attrs . ProcAttributes . objc_accessor with
match attrs . ProcAttributes . objc_accessor with
| Some objc_accessor ->
| Some objc_accessor ->
(* If it's an ObjC getter or setter, call the builtin rather than skipping *)
(* If it's an ObjC getter or setter, call the builtin rather than skipping *)
handle_objc_instance_method_call n_actual_params n_actual_params prop
handle_objc_instance_method_call n_actual_params prop tenv
tenv ( fst ret_id_typ ) current_pdesc resolved_pname loc path
( fst ret_id_typ ) current_pdesc resolved_pname path ( fun () ->
( sym_exec_objc_accessor resolved_pname objc_accessor ret_type )
sym_exec_objc_accessor resolved_pname objc_accessor ret_type tenv
( fst ret_id_typ ) current_pdesc callee_pname loc n_actual_params
prop path )
| None when model_as_malloc ret_type resolved_pname ->
| None when model_as_malloc ret_type resolved_pname ->
(* If it's an alloc model, call alloc rather than skipping *)
(* If it's an alloc model, call alloc rather than skipping *)
sym_exec_alloc_model exe_env resolved_pname ret_type tenv ret_id_typ
sym_exec_alloc_model analysis_data resolved_pname ret_type ret_id_typ
current_summary loc prop path
loc prop path
| _ ->
| _ ->
let is_objc_instance_method =
let is_objc_instance_method =
ClangMethodKind . equal attrs . ProcAttributes . clang_method_kind
ClangMethodKind . equal attrs . ProcAttributes . clang_method_kind
@ -1422,7 +1403,7 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
skip_call ~ reason prop path resolved_pname ret_annots loc ret_id_typ
skip_call ~ reason prop path resolved_pname ret_annots loc ret_id_typ
( snd ret_id_typ ) n_actual_params )
( snd ret_id_typ ) n_actual_params )
| None ->
| None ->
proc_call exe_env
proc_call
( Option . value_exn resolved_summary_opt )
( Option . value_exn resolved_summary_opt )
( call_args prop resolved_pname n_actual_params ret_id_typ loc )
( call_args prop resolved_pname n_actual_params ret_id_typ loc )
in
in
@ -1441,17 +1422,14 @@ let rec sym_exec exe_env tenv current_summary instr_ (prop_ : Prop.normal Prop.t
let callee_pname = Procname . from_string_c_fun " __function_pointer__ " in
let callee_pname = Procname . from_string_c_fun " __function_pointer__ " in
unknown_or_scan_call ~ is_scan : false ~ reason : " unresolved function pointer " ( snd ret_id_typ )
unknown_or_scan_call ~ is_scan : false ~ reason : " unresolved function pointer " ( snd ret_id_typ )
Annot . Item . empty
Annot . Item . empty
Builtin .
{ Builtin . analysis_data
{ summary = current_summary
; instr
; instr
; prop_ = prop_r
; tenv
; path
; prop_ = prop_r
; ret_id_typ
; path
; args = n_actual_params
; ret_id_typ
; proc_name = callee_pname
; args = n_actual_params
; loc }
; proc_name = callee_pname
; loc
; exe_env }
| Sil . Metadata ( Nullify ( pvar , _ ) ) -> (
| Sil . Metadata ( Nullify ( pvar , _ ) ) -> (
let eprop = Prop . expose prop_ in
let eprop = Prop . expose prop_ in
match
match
@ -1494,12 +1472,12 @@ and diverge prop path =
(* * Symbolic execution of a sequence of instructions. If errors occur and [mask_errors] is true,
(* * Symbolic execution of a sequence of instructions. If errors occur and [mask_errors] is true,
just treat as skip . * )
just treat as skip . * )
and instrs ? ( mask_errors = false ) exe_env tenv summary instrs ppl =
and instrs ? ( mask_errors = false ) analysis_data instrs ppl =
let exe_instr instr ( p , path ) =
let exe_instr instr ( p , path ) =
L . d_str " Executing Generated Instruction " ;
L . d_str " Executing Generated Instruction " ;
Sil . d_instr instr ;
Sil . d_instr instr ;
L . d_ln () ;
L . d_ln () ;
try sym_exec exe_env tenv summary instr p path
try sym_exec analysis_data instr p path
with exn ->
with exn ->
IExn . reraise_if exn ~ f : ( fun () -> ( not mask_errors ) | | not ( SymOp . exn_not_failure exn ) ) ;
IExn . reraise_if exn ~ f : ( fun () -> ( not mask_errors ) | | not ( SymOp . exn_not_failure exn ) ) ;
let error = Exceptions . recognize_exception exn in
let error = Exceptions . recognize_exception exn in
@ -1607,8 +1585,14 @@ and add_constraints_on_actuals_by_ref tenv caller_pdesc prop actuals_by_ref call
(* * execute a call for an unknown or scan function *)
(* * execute a call for an unknown or scan function *)
and unknown_or_scan_call ~ is_scan ~ reason ret_typ ret_annots
and unknown_or_scan_call ~ is_scan ~ reason ret_typ ret_annots
{ Builtin . tenv ; summary ; prop_ = pre ; path ; ret_id_typ ; args ; proc_name = callee_pname ; loc ; instr }
{ Builtin . analysis_data = { proc_desc ; tenv ; _ }
=
; prop_ = pre
; path
; ret_id_typ
; args
; proc_name = callee_pname
; loc
; instr } =
let remove_file_attribute prop =
let remove_file_attribute prop =
let do_exp p ( e , _ ) =
let do_exp p ( e , _ ) =
let do_attribute q atom =
let do_attribute q atom =
@ -1662,16 +1646,15 @@ and unknown_or_scan_call ~is_scan ~reason ret_typ ret_annots
in
in
let has_nonnull_annot = Annotations . ia_is_nonnull ret_annots in
let has_nonnull_annot = Annotations . ia_is_nonnull ret_annots in
let pre_final =
let pre_final =
let pdesc = Summary . get_proc_desc summary in
(* in Java, assume that skip functions close resources passed as params *)
(* in Java, assume that skip functions close resources passed as params *)
let pre_1 = if Procname . is_java callee_pname then remove_file_attribute pre else pre in
let pre_1 = if Procname . is_java callee_pname then remove_file_attribute pre else pre in
let pre_2 =
let pre_2 =
(* TODO ( jjb ) : Should this use the type of ret_id, or ret_type from the procedure type? *)
(* TODO ( jjb ) : Should this use the type of ret_id, or ret_type from the procedure type? *)
add_constraints_on_retval tenv p desc pre_1
add_constraints_on_retval tenv p roc_ desc pre_1
( Exp . Var ( fst ret_id_typ ) )
( Exp . Var ( fst ret_id_typ ) )
ret_typ ~ has_nonnull_annot callee_pname loc
ret_typ ~ has_nonnull_annot callee_pname loc
in
in
add_constraints_on_actuals_by_ref tenv p desc pre_2 actuals_by_ref callee_pname loc
add_constraints_on_actuals_by_ref tenv p roc_ desc pre_2 actuals_by_ref callee_pname loc
in
in
if is_scan (* if scan function, don't mark anything with undef attributes *) then
if is_scan (* if scan function, don't mark anything with undef attributes *) then
[ ( Tabulation . remove_constant_string_class tenv pre_final , path ) ]
[ ( Tabulation . remove_constant_string_class tenv pre_final , path ) ]
@ -1694,7 +1677,7 @@ and unknown_or_scan_call ~is_scan ~reason ret_typ ret_annots
and check_variadic_sentinel ? ( fails_on_nil = false ) n_formals ( sentinel , null_pos )
and check_variadic_sentinel ? ( fails_on_nil = false ) n_formals ( sentinel , null_pos )
{ Builtin . summary; tenv ; prop_ ; path ; args ; proc_name ; loc ; exe_env } =
{ Builtin . analysis_data= { tenv ; _ } as analysis_data ; prop_ ; path ; args ; proc_name ; loc } =
(* from clang's lib/Sema/SemaExpr.cpp: *)
(* from clang's lib/Sema/SemaExpr.cpp: *)
(* "nullPos" is the number of formal parameters at the end which *)
(* "nullPos" is the number of formal parameters at the end which *)
(* effectively count as part of the variadic arguments. This is *)
(* effectively count as part of the variadic arguments. This is *)
@ -1713,7 +1696,7 @@ and check_variadic_sentinel ?(fails_on_nil = false) n_formals (sentinel, null_po
(* simulate a Load for [lexp] *)
(* simulate a Load for [lexp] *)
let tmp_id_deref = Ident . create_fresh Ident . kprimed in
let tmp_id_deref = Ident . create_fresh Ident . kprimed in
let load_instr = Sil . Load { id = tmp_id_deref ; e = lexp ; root_typ = typ ; typ ; loc } in
let load_instr = Sil . Load { id = tmp_id_deref ; e = lexp ; root_typ = typ ; typ ; loc } in
try instrs exe_env tenv summary ( Instrs . singleton load_instr ) result
try instrs analysis_data ( Instrs . singleton load_instr ) result
with e when SymOp . exn_not_failure e ->
with e when SymOp . exn_not_failure e ->
IExn . reraise_if e ~ f : ( fun () -> fails_on_nil ) ;
IExn . reraise_if e ~ f : ( fun () -> fails_on_nil ) ;
let deref_str = Localise . deref_str_nil_argument_in_variadic_method proc_name nargs i in
let deref_str = Localise . deref_str_nil_argument_in_variadic_method proc_name nargs i in
@ -1794,8 +1777,7 @@ and sym_exec_objc_accessor callee_pname property_accesor ret_typ tenv ret_id pde
f_accessor ret_typ tenv ret_id pdesc cur_pname loc args prop | > List . map ~ f : ( fun p -> ( p , path ) )
f_accessor ret_typ tenv ret_id pdesc cur_pname loc args prop | > List . map ~ f : ( fun p -> ( p , path ) )
and sym_exec_alloc_model exe_env pname ret_typ tenv ret_id_typ summary loc prop path :
and sym_exec_alloc_model analysis_data pname ret_typ ret_id_typ loc prop path : Builtin . ret_typ =
Builtin . ret_typ =
let alloc_source_function_arg = ( Exp . Const ( Const . Cfun pname ) , Typ . void ) in
let alloc_source_function_arg = ( Exp . Const ( Const . Cfun pname ) , Typ . void ) in
let args =
let args =
let sizeof_exp =
let sizeof_exp =
@ -1807,17 +1789,22 @@ and sym_exec_alloc_model exe_env pname ret_typ tenv ret_id_typ summary loc prop
let alloc_fun = Exp . Const ( Const . Cfun BuiltinDecl . malloc_no_fail ) in
let alloc_fun = Exp . Const ( Const . Cfun BuiltinDecl . malloc_no_fail ) in
let alloc_instr = Sil . Call ( ret_id_typ , alloc_fun , args , loc , CallFlags . default ) in
let alloc_instr = Sil . Call ( ret_id_typ , alloc_fun , args , loc , CallFlags . default ) in
L . d_strln " No spec found, method should be model as alloc, executing alloc... " ;
L . d_strln " No spec found, method should be model as alloc, executing alloc... " ;
instrs exe_env tenv summary ( Instrs . singleton alloc_instr ) [ ( prop , path ) ]
instrs analysis_data ( Instrs . singleton alloc_instr ) [ ( prop , path ) ]
(* * Perform symbolic execution for a function call *)
(* * Perform symbolic execution for a function call *)
and proc_call exe_env callee_summary
and proc_call ( callee_pdesc , callee_summary )
{ Builtin . summary ; tenv ; prop_ = pre ; path ; ret_id_typ ; args = actual_pars ; loc } =
{ Builtin . analysis_data = { proc_desc = caller_pdesc ; tenv ; _ } as analysis_data
let caller_pname = Summary . get_proc_name summary in
; prop_ = pre
let callee_attrs = Summary . get_attributes callee_summary in
; path
let callee_pname = Summary . get_proc_name callee_summary in
; ret_id_typ
; args = actual_pars
; loc } =
let caller_pname = Procdesc . get_proc_name caller_pdesc in
let callee_pname = Procdesc . get_proc_name callee_pdesc in
let callee_attributes = Procdesc . get_attributes callee_pdesc in
check_inherently_dangerous_function caller_pname callee_pname ;
check_inherently_dangerous_function caller_pname callee_pname ;
let formal_types = List . map ~ f : snd ( Summary . get_formals callee_summary ) in
let formal_types = List . map ~ f : snd callee_attributes . ProcAttributes . formals in
let rec comb actual_pars formal_types =
let rec comb actual_pars formal_types =
match ( actual_pars , formal_types ) with
match ( actual_pars , formal_types ) with
| [] , [] ->
| [] , [] ->
@ -1851,23 +1838,23 @@ and proc_call exe_env callee_summary
parameter type if there are enough formal parameters , and
parameter type if there are enough formal parameters , and
to their actual type otherwise . The latter case happens
to their actual type otherwise . The latter case happens
with variable - arguments functions * )
with variable - arguments functions * )
let actual _param s = comb actual_pars formal_types in
let actual s = comb actual_pars formal_types in
(* In case we call an objc instance method we add an extra spec
(* In case we call an objc instance method we add an extra spec
where the receiver is null and the semantics of the call is nop * )
where the receiver is null and the semantics of the call is nop * )
let pdesc = Summary . get_proc_desc summary in
match ( ! Language . curr_language , callee_attributes . ProcAttributes . clang_method_kind ) with
match ( ! Language . curr_language , callee_attrs . ProcAttributes . clang_method_kind ) with
| Language . Clang , ClangMethodKind . OBJC_INSTANCE ->
| Language . Clang , ClangMethodKind . OBJC_INSTANCE ->
handle_objc_instance_method_call actual_pars actual_params pre tenv ( fst ret_id_typ ) pdesc
handle_objc_instance_method_call actual_pars pre tenv ( fst ret_id_typ ) caller_pdesc
callee_pname loc path
callee_pname path ( fun () ->
( Tabulation . exe_function_call exe_env callee_summary )
Tabulation . exe_function_call analysis_data ~ callee_attributes ~ callee_pname
~ callee_summary ~ ret_id : ( fst ret_id_typ ) loc ~ actuals pre path )
| _ ->
| _ ->
(* non-objective-c method call. Standard tabulation *)
(* non-objective-c method call. Standard tabulation *)
Tabulation . exe_function_call exe_env callee_summary tenv ( fst ret_id_typ ) pdesc callee_pname
Tabulation . exe_function_call analysis_data ~ callee_summary ~ ret_id : ( fst ret_id_typ )
loc actual _param s pre path
~ callee_pname ~ callee_attributes loc ~ actual s pre path
(* * perform symbolic execution for a single prop, and check for junk *)
(* * perform symbolic execution for a single prop, and check for junk *)
and sym_exec_wrapper exe_env handle_exn tenv summary proc_cfg instr
and sym_exec_wrapper ( { InterproceduralAnalysis . tenv ; _ } as analysis_data ) handle_exn proc_cfg instr
( ( prop : Prop . normal Prop . t ) , path ) : Paths . PathSet . t =
( ( prop : Prop . normal Prop . t ) , path ) : Paths . PathSet . t =
let pname = Procdesc . get_proc_name ( ProcCfg . Exceptional . proc_desc proc_cfg ) in
let pname = Procdesc . get_proc_name ( ProcCfg . Exceptional . proc_desc proc_cfg ) in
let prop_primed_to_normal p =
let prop_primed_to_normal p =
@ -1911,7 +1898,7 @@ and sym_exec_wrapper exe_env handle_exn tenv summary proc_cfg instr
(* Check for retain cycles after assignments and method calls *)
(* Check for retain cycles after assignments and method calls *)
( match instr with
( match instr with
| ( Sil . Store _ | Sil . Call _ ) when ! BiabductionConfig . footprint ->
| ( Sil . Store _ | Sil . Call _ ) when ! BiabductionConfig . footprint ->
RetainCycles . report_cycle tenv summary p
RetainCycles . report_cycle analysis_data p
| _ ->
| _ ->
() ) ;
() ) ;
let node_has_abstraction node =
let node_has_abstraction node =
@ -1934,7 +1921,7 @@ and sym_exec_wrapper exe_env handle_exn tenv summary proc_cfg instr
let res_list =
let res_list =
BiabductionConfig . run_with_abs_val_equal_zero
BiabductionConfig . run_with_abs_val_equal_zero
(* no exp abstraction during sym exe *)
(* no exp abstraction during sym exe *)
( fun () -> sym_exec exe_env tenv summary instr prop' path )
( fun () -> sym_exec analysis_data instr prop' path )
()
()
in
in
let res_list_nojunk =
let res_list_nojunk =
@ -1960,7 +1947,7 @@ and sym_exec_wrapper exe_env handle_exn tenv summary proc_cfg instr
(* * {2 Lifted Abstract Transfer Functions} *)
(* * {2 Lifted Abstract Transfer Functions} *)
let node handle_exn exe_env tenv summary proc_cfg ( node : ProcCfg . Exceptional . Node . t )
let node handle_exn analysis_data proc_cfg ( node : ProcCfg . Exceptional . Node . t )
( pset : Paths . PathSet . t ) : Paths . PathSet . t =
( pset : Paths . PathSet . t ) : Paths . PathSet . t =
let pname = Procdesc . get_proc_name ( ProcCfg . Exceptional . proc_desc proc_cfg ) in
let pname = Procdesc . get_proc_name ( ProcCfg . Exceptional . proc_desc proc_cfg ) in
let exe_instr_prop instr p tr ( pset1 : Paths . PathSet . t ) =
let exe_instr_prop instr p tr ( pset1 : Paths . PathSet . t ) =
@ -1979,7 +1966,7 @@ let node handle_exn exe_env tenv summary proc_cfg (node : ProcCfg.Exceptional.No
Sil . d_instr instr ;
Sil . d_instr instr ;
L . d_strln " due to exception " ;
L . d_strln " due to exception " ;
Paths . PathSet . from_renamed_list [ ( p , tr ) ] )
Paths . PathSet . from_renamed_list [ ( p , tr ) ] )
else sym_exec_wrapper exe_env handle_exn tenv summary proc_cfg instr ( p , tr )
else sym_exec_wrapper analysis_data handle_exn proc_cfg instr ( p , tr )
in
in
Paths . PathSet . union pset2 pset1
Paths . PathSet . union pset2 pset1
in
in