[nullsafe] stop using SummaryReporting

Summary:
This turned into a pretty big refactoring: the
`IntraproceduralAnalysis.t` needs to be passed around through quite a
few functions. These functions usually depended on
tenv/proc_desc/proc_name that are already in the `analysis_data` so
refactored that too (checking that these were indeed the same as in the
`analysis_data` record (using my own eyeballs). Interestingly there is
one place where we actually turn the analysis to other proc descs than
the original one in eradicate.ml so I've added a small comment there.

Reviewed By: mityal

Differential Revision: D21351909

fbshipit-source-id: 6e6330e5b
master
Jules Villard 5 years ago committed by Facebook GitHub Bot
parent bab005a835
commit f86d9193a9

@ -6,7 +6,6 @@
*)
open! IStd
module L = Logging
type log_t = Reporting.log_t
@ -25,18 +24,3 @@ let log_warning summary ~loc ?ltr ?extras issue_type error_message =
let log_error_using_state summary exn =
BiabductionReporting.log_error_using_state (Summary.get_proc_desc summary)
(Summary.get_err_log summary) exn
let log_issue_deprecated_using_state severity proc_name ?node ?loc ?ltr exn =
if !BiabductionConfig.footprint then
match Summary.OnDisk.get proc_name with
| Some summary ->
let proc_attributes = Summary.get_attributes summary in
let err_log = Summary.get_err_log summary in
BiabductionReporting.log_issue_deprecated_using_state proc_attributes err_log severity ?node
?loc ?ltr exn
| None ->
L.(die InternalError)
"Trying to report error on procedure %a, but cannot because no summary exists for this \
procedure. Did you mean to log the error on the caller of %a instead?"
Procname.pp proc_name Procname.pp proc_name

@ -19,14 +19,3 @@ val log_warning : Summary.t -> loc:Location.t -> log_t
val log_error_using_state : Summary.t -> exn -> unit
(** Add an error to the given summary using biabduction state (DO NOT USE ELSEWHERE). *)
val log_issue_deprecated_using_state :
Exceptions.severity
-> Procname.t
-> ?node:Procdesc.Node.t
-> ?loc:Location.t
-> ?ltr:Errlog.loc_trace
-> exn
-> unit
(** Report an issue in the given procedure using biabduction state. DEPRECATED as it can create race
conditions between checkers. Use log_error_using_state instead *)

@ -10,8 +10,10 @@ module L = Logging
module F = Format
open Dataflow
let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname curr_pdesc
annotated_signature linereader proc_loc : bool * TypeState.t option =
let callback1 ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data)
find_canonical_duplicate calls_this checks idenv annotated_signature linereader proc_loc :
bool * TypeState.t option =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let add_formal typestate (param_signature : AnnotatedSignature.param_signature) =
let pvar = Pvar.mk param_signature.mangled curr_pname in
let formal_name = param_signature.mangled in
@ -37,7 +39,7 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c
(* Check the nullable flag computed for the return value and report inconsistencies. *)
let check_return find_canonical_duplicate exit_node final_typestate annotated_signature loc : unit
=
let AnnotatedSignature.{ret_annotated_type} = annotated_signature.AnnotatedSignature.ret in
let {AnnotatedSignature.ret_annotated_type} = annotated_signature.AnnotatedSignature.ret in
let ret_pvar = Procdesc.get_ret_var curr_pdesc in
let ret_range = TypeState.lookup_pvar ret_pvar final_typestate in
let typ_found_opt =
@ -50,10 +52,10 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c
AnalysisState.set_node exit_node ;
if not (List.is_empty checks.TypeCheck.check_ret_type) then
List.iter
~f:(fun f -> f curr_pname curr_pdesc ret_annotated_type.typ typ_found_opt loc)
~f:(fun f -> f curr_pdesc ret_annotated_type.typ typ_found_opt loc)
checks.TypeCheck.check_ret_type ;
if checks.TypeCheck.eradicate then
EradicateChecks.check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
EradicateChecks.check_return_annotation analysis_data find_canonical_duplicate ret_range
annotated_signature ret_implicitly_nullable loc
in
let do_before_dataflow initial_typestate =
@ -73,13 +75,13 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c
let pp_name fmt = F.pp_print_string fmt "eradicate"
let do_node tenv node typestate =
let do_node _tenv node typestate =
NodePrinter.with_session ~pp_name node ~f:(fun () ->
AnalysisState.set_node node ;
if Config.write_html then L.d_printfln "before:@\n%a@\n" TypeState.pp typestate ;
let TypeCheck.{normal_flow_typestate; exception_flow_typestates} =
TypeCheck.typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc
find_canonical_duplicate annotated_signature typestate node linereader
let {TypeCheck.normal_flow_typestate; exception_flow_typestates} =
TypeCheck.typecheck_node analysis_data calls_this checks idenv find_canonical_duplicate
annotated_signature typestate node linereader
in
let normal_flow_typestates =
Option.value_map normal_flow_typestate ~f:(fun a -> [a]) ~default:[]
@ -100,14 +102,15 @@ let callback1 tenv find_canonical_duplicate calls_this checks idenv curr_pname c
(!calls_this, None)
let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_signature linereader
proc_loc : unit =
let analyze_one_procedure ({IntraproceduralAnalysis.tenv; proc_desc; _} as analysis_data) calls_this
checks annotated_signature linereader proc_loc : unit =
let idenv = Idenv.create proc_desc in
let find_duplicate_nodes = State.mk_find_duplicate_nodes proc_desc in
let find_canonical_duplicate node =
let duplicate_nodes = find_duplicate_nodes node in
try Procdesc.NodeSet.min_elt duplicate_nodes with Caml.Not_found -> node
in
let proc_name = Procdesc.get_proc_name proc_desc in
let caller_nullsafe_mode = NullsafeMode.of_procname tenv proc_name in
let typecheck_proc do_checks pname pdesc proc_details_opt =
let ann_sig, loc, idenv_pn =
@ -134,8 +137,10 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s
if do_checks then (checks, calls_this)
else ({TypeCheck.eradicate= false; check_ret_type= []}, ref false)
in
callback1 tenv find_canonical_duplicate calls_this' checks' idenv_pn pname pdesc ann_sig
linereader loc
(* NOTE: [analysis_data] has the new [pdesc] *)
callback1
{analysis_data with proc_desc= pdesc}
find_canonical_duplicate calls_this' checks' idenv_pn ann_sig linereader loc
in
let do_final_typestate typestate_opt calls_this =
let do_typestate typestate =
@ -151,8 +156,8 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s
let typestates_for_all_constructors_incl_current =
Initializers.final_constructor_typestates_lazy tenv proc_name typecheck_proc
in
EradicateChecks.check_constructor_initialization tenv find_canonical_duplicate proc_name
proc_desc start_node ~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode
EradicateChecks.check_constructor_initialization analysis_data find_canonical_duplicate
start_node ~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode
~typestates_for_curr_constructor_and_all_initializer_methods
~typestates_for_all_constructors_incl_current proc_loc ;
if Config.eradicate_verbose then L.result "Final Typestate@\n%a@." TypeState.pp typestate )
@ -164,7 +169,7 @@ let analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_s
in
do_final_typestate final_typestate_opt calls_this ;
if checks.TypeCheck.eradicate then
EradicateChecks.check_overridden_annotations find_canonical_duplicate tenv proc_name proc_desc
EradicateChecks.check_overridden_annotations analysis_data find_canonical_duplicate
annotated_signature ;
()
@ -188,7 +193,8 @@ let find_reason_to_skip_analysis proc_name proc_desc =
(** Entry point for the nullsafe procedure-level analysis. *)
let analyze checks {IntraproceduralAnalysis.proc_desc; tenv} : NullsafeSummary.t option =
let analyze checks ({IntraproceduralAnalysis.proc_desc; tenv; _} as analysis_data) :
NullsafeSummary.t option =
let proc_name = Procdesc.get_proc_name proc_desc in
L.debug Analysis Medium "Analysis of %a@\n" Procname.pp proc_name ;
match find_reason_to_skip_analysis proc_name proc_desc with
@ -210,14 +216,12 @@ let analyze checks {IntraproceduralAnalysis.proc_desc; tenv} : NullsafeSummary.t
(* The main method - during this the actual analysis will happen and TypeErr will be populated with
issues (and some of them - reported).
*)
analyze_one_procedure tenv proc_name proc_desc calls_this checks annotated_signature
linereader loc ;
analyze_one_procedure analysis_data calls_this checks annotated_signature linereader loc ;
(* Collect issues that were detected during analysis and put them in summary for further processing *)
let issues = TypeErr.get_errors () |> List.map ~f:(fun (issues, _) -> issues) in
(* Report errors of "farall" class - those could not be reported during analysis phase. *)
TypeErr.report_forall_issues_and_reset
(EradicateCheckers.report_error tenv)
~nullsafe_mode:annotated_signature.nullsafe_mode proc_desc ;
TypeErr.report_forall_issues_and_reset analysis_data
~nullsafe_mode:annotated_signature.nullsafe_mode ;
Some {NullsafeSummary.issues}

@ -9,7 +9,7 @@ open! IStd
(** Module for Eradicate-based user-defined checkers. *)
let report_error tenv proc_name proc_desc kind loc ?(field_name = None)
let report_error {IntraproceduralAnalysis.proc_desc; tenv; err_log} kind loc ?(field_name = None)
?(exception_kind = fun k d -> Exceptions.Checkers (k, d)) ~severity description =
let suppressed = Reporting.is_suppressed tenv proc_desc kind ~field_name in
if suppressed then Logging.debug Analysis Medium "Reporting is suppressed!@\n"
@ -17,4 +17,9 @@ let report_error tenv proc_name proc_desc kind loc ?(field_name = None)
let localized_description = Localise.verbatim_desc description in
let exn = exception_kind kind localized_description in
let trace = [Errlog.make_trace_element 0 loc description []] in
SummaryReporting.log_issue_deprecated_using_state severity proc_name ~loc ~ltr:trace exn
let attrs = Procdesc.get_attributes proc_desc in
let node = AnalysisState.get_node_exn () in
let session = AnalysisState.get_session () in
Reporting.log_issue_from_summary severity attrs err_log
~node:(BackendNode {node})
~session ~loc ~ltr:trace exn

@ -10,9 +10,7 @@ open! IStd
(** Module for Eradicate-based user-defined checkers. *)
val report_error :
Tenv.t
-> Procname.t
-> Procdesc.t
IntraproceduralAnalysis.t
-> IssueType.t
-> Location.t
-> ?field_name:Fieldname.t option

@ -11,8 +11,6 @@ open! IStd
module L = Logging
let register_error tenv = TypeErr.register_error (EradicateCheckers.report_error tenv)
let explain_expr tenv node e =
match Errdesc.exp_rv_dexp tenv node e with
| Some de ->
@ -28,8 +26,8 @@ let is_virtual = function
false
let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pname node instr_ref
object_exp dereference_type inferred_nullability loc =
let check_object_dereference ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode
find_canonical_duplicate node instr_ref object_exp dereference_type inferred_nullability loc =
Result.iter_error
(DereferenceRule.check (InferredNullability.get_nullability inferred_nullability))
~f:(fun dereference_violation ->
@ -43,15 +41,17 @@ let check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_p
; dereference_type
; nullable_object_origin }
in
register_error tenv find_canonical_duplicate type_error (Some instr_ref) ~nullsafe_mode loc
curr_pname )
TypeErr.register_error analysis_data find_canonical_duplicate type_error (Some instr_ref)
~nullsafe_mode loc )
(** [expr] is an expression that was explicitly compared with `null`. At the same time, [expr] had
[inferred_nullability] before the comparision. Check if the comparision is redundant and emit an
issue, if this is the case. *)
let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate curr_pdesc node
~nullsafe_mode expr typ inferred_nullability idenv linereader loc instr_ref : unit =
let check_condition_for_redundancy
({IntraproceduralAnalysis.tenv; proc_desc= curr_pdesc; _} as analysis_data) ~is_always_true
find_canonical_duplicate node ~nullsafe_mode expr typ inferred_nullability idenv linereader loc
instr_ref : unit =
let contains_instanceof_throwable pdesc node =
(* Check if the current procedure has a catch Throwable. *)
(* That always happens in the bytecode generated by try-with-resources. *)
@ -111,21 +111,22 @@ let check_condition_for_redundancy tenv ~is_always_true find_canonical_duplicate
*)
let condition_descr = explain_expr tenv node expr in
let nonnull_origin = InferredNullability.get_origin inferred_nullability in
register_error tenv find_canonical_duplicate
TypeErr.register_error analysis_data find_canonical_duplicate
(TypeErr.Condition_redundant {is_always_true; condition_descr; nonnull_origin})
(Some instr_ref) ~nullsafe_mode loc curr_pdesc
(Some instr_ref) ~nullsafe_mode loc
(** Check an assignment to a field. *)
let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node instr_ref
typestate ~expr_rhs ~field_type loc fname (annotated_field : AnnotatedField.t) typecheck_expr :
unit =
let check_field_assignment
({IntraproceduralAnalysis.tenv; proc_desc= curr_pdesc; _} as analysis_data) ~nullsafe_mode
find_canonical_duplicate node instr_ref typestate ~expr_rhs ~field_type loc fname
(annotated_field : AnnotatedField.t) typecheck_expr : unit =
L.d_with_indent ~name:"check_field_assignment" (fun () ->
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let curr_pattrs = Procdesc.get_attributes curr_pdesc in
let _, inferred_nullability_rhs =
L.d_strln "Typechecking rhs" ;
typecheck_expr node instr_ref curr_pdesc typestate expr_rhs
typecheck_expr node instr_ref typestate expr_rhs
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(field_type, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
@ -158,13 +159,13 @@ let check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate curr_pde
in
if should_report then
let rhs_origin = InferredNullability.get_origin inferred_nullability_rhs in
register_error tenv find_canonical_duplicate
TypeErr.register_error analysis_data find_canonical_duplicate
(TypeErr.Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type= AssignmentRule.ReportableViolation.AssigningToField fname })
(Some instr_ref) ~nullsafe_mode loc curr_pdesc ) )
(Some instr_ref) ~nullsafe_mode loc ) )
(* Check if the field declared as not nullable (implicitly or explicitly). If the field is
@ -228,12 +229,13 @@ let is_generated_field field_name =
(** Check field initialization for a given constructor *)
let check_constructor_initialization tenv find_canonical_duplicate curr_constructor_pname
curr_constructor_pdesc start_node ~nullsafe_mode
let check_constructor_initialization
({IntraproceduralAnalysis.tenv; proc_desc= curr_constructor_pdesc; _} as analysis_data)
find_canonical_duplicate start_node ~nullsafe_mode
~typestates_for_curr_constructor_and_all_initializer_methods
~typestates_for_all_constructors_incl_current loc : unit =
AnalysisState.set_node start_node ;
if Procname.is_constructor curr_constructor_pname then
if Procname.is_constructor (Procdesc.get_proc_name curr_constructor_pdesc) then
match
PatternMatch.get_this_type_nonstatic_methods_only
(Procdesc.get_attributes curr_constructor_pdesc)
@ -305,9 +307,9 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
*)
()
else
register_error tenv find_canonical_duplicate
TypeErr.register_error analysis_data find_canonical_duplicate
(TypeErr.Field_not_initialized {field_name})
None ~nullsafe_mode loc curr_constructor_pdesc ;
None ~nullsafe_mode loc ;
(* Check if field is over-annotated. *)
match annotated_field with
| None ->
@ -321,11 +323,11 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
let by_rhs_upper_bound = field_nullability_upper_bound_over_all_typestates () in
Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound)
~f:(fun over_annotated_violation ->
register_error tenv find_canonical_duplicate
TypeErr.register_error analysis_data find_canonical_duplicate
(TypeErr.Over_annotation
{ over_annotated_violation
; violation_type= OverAnnotatedRule.FieldOverAnnoted field_name })
~nullsafe_mode None loc curr_constructor_pdesc ) )
~nullsafe_mode None loc ) )
in
List.iter ~f:do_field fields
| None ->
@ -334,24 +336,27 @@ let check_constructor_initialization tenv find_canonical_duplicate curr_construc
()
let check_return_not_nullable ~nullsafe_mode tenv find_canonical_duplicate loc curr_pname curr_pdesc
(ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
let check_return_not_nullable ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data)
~nullsafe_mode find_canonical_duplicate loc (ret_signature : AnnotatedSignature.ret_signature)
ret_inferred_nullability =
(* Returning from a function is essentially an assignment the actual return value to the formal `return` *)
let lhs = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in
let rhs = InferredNullability.get_nullability ret_inferred_nullability in
Result.iter_error (AssignmentRule.check ~lhs ~rhs) ~f:(fun assignment_violation ->
let rhs_origin = InferredNullability.get_origin ret_inferred_nullability in
register_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
let curr_pname = Procdesc.get_proc_name curr_pdesc in
TypeErr.register_error analysis_data find_canonical_duplicate
(Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type= AssignmentRule.ReportableViolation.ReturningFromFunction curr_pname })
None ~nullsafe_mode loc curr_pdesc )
; assignment_type= ReturningFromFunction curr_pname })
None ~nullsafe_mode loc )
let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc
~nullsafe_mode (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
let check_return_overrannotated
({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data) find_canonical_duplicate
loc ~nullsafe_mode (ret_signature : AnnotatedSignature.ret_signature) ret_inferred_nullability =
(* Returning from a function is essentially an assignment the actual return value to the formal `return` *)
let what = AnnotatedNullability.get_nullability ret_signature.ret_annotated_type.nullability in
(* In our CFG implementation, there is only one place where we return from a function
@ -361,34 +366,29 @@ let check_return_overrannotated tenv find_canonical_duplicate loc curr_pname cur
let by_rhs_upper_bound = InferredNullability.get_nullability ret_inferred_nullability in
Result.iter_error (OverAnnotatedRule.check ~what ~by_rhs_upper_bound)
~f:(fun over_annotated_violation ->
register_error tenv find_canonical_duplicate
(TypeErr.Over_annotation
{ over_annotated_violation
; violation_type= OverAnnotatedRule.ReturnOverAnnotated curr_pname })
None ~nullsafe_mode loc curr_pdesc )
let curr_pname = Procdesc.get_proc_name curr_pdesc in
TypeErr.register_error analysis_data find_canonical_duplicate
(Over_annotation {over_annotated_violation; violation_type= ReturnOverAnnotated curr_pname})
None ~nullsafe_mode loc )
(** Check the annotations when returning from a method. *)
let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
(annotated_signature : AnnotatedSignature.t) ret_implicitly_nullable loc : unit =
let check_return_annotation ({IntraproceduralAnalysis.proc_desc= curr_pdesc; _} as analysis_data)
find_canonical_duplicate ret_range (annotated_signature : AnnotatedSignature.t)
ret_implicitly_nullable loc : unit =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
match ret_range with
(* Disables the warnings since it is not clear how to annotate the return value of lambdas *)
| Some _
when match curr_pname with
| Procname.Java java_pname ->
Procname.Java.is_lambda java_pname
| _ ->
false ->
when match curr_pname with Java java_pname -> Procname.Java.is_lambda java_pname | _ -> false ->
()
| Some (_, ret_inferred_nullability) ->
(* TODO(T54308240) Model ret_implicitly_nullable in AnnotatedNullability *)
if not ret_implicitly_nullable then
check_return_not_nullable ~nullsafe_mode:annotated_signature.nullsafe_mode tenv
find_canonical_duplicate loc curr_pname curr_pdesc annotated_signature.ret
ret_inferred_nullability ;
check_return_not_nullable analysis_data ~nullsafe_mode:annotated_signature.nullsafe_mode
find_canonical_duplicate loc annotated_signature.ret ret_inferred_nullability ;
if Config.eradicate_return_over_annotated then
check_return_overrannotated tenv find_canonical_duplicate loc curr_pname curr_pdesc
check_return_overrannotated analysis_data find_canonical_duplicate loc
annotated_signature.ret ~nullsafe_mode:annotated_signature.nullsafe_mode
ret_inferred_nullability
| None ->
@ -396,18 +396,18 @@ let check_return_annotation tenv find_canonical_duplicate curr_pdesc ret_range
(** Check the receiver of a virtual call. *)
let check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node typestate
let check_call_receiver analysis_data ~nullsafe_mode find_canonical_duplicate node typestate
call_params callee_pname (instr_ref : TypeErr.InstrRef.t) loc typecheck_expr : unit =
match call_params with
| ((original_this_e, this_e), typ) :: _ ->
let _, this_inferred_nullability =
typecheck_expr tenv node instr_ref curr_pdesc typestate this_e
typecheck_expr node instr_ref typestate this_e
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(typ, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
in
check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc node
instr_ref original_this_e (DereferenceRule.ReportableViolation.MethodCall callee_pname)
check_object_dereference analysis_data ~nullsafe_mode find_canonical_duplicate node instr_ref
original_this_e (DereferenceRule.ReportableViolation.MethodCall callee_pname)
this_inferred_nullability loc
| [] ->
()
@ -420,8 +420,9 @@ type resolved_param =
; is_formal_propagates_nullable: bool }
(** Check the parameters of a call. *)
let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_canonical_duplicate
curr_pdesc node callee_attributes resolved_params loc instr_ref : unit =
let check_call_parameters ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode
~callee_annotated_signature find_canonical_duplicate node callee_attributes resolved_params loc
instr_ref : unit =
let callee_pname = callee_attributes.ProcAttributes.proc_name in
let check {num= param_position; formal; actual= orig_e2, nullability_actual} =
let report ~nullsafe_mode assignment_violation =
@ -433,19 +434,19 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c
"formal parameter " ^ Mangled.to_string formal.mangled
in
let rhs_origin = InferredNullability.get_origin nullability_actual in
register_error tenv find_canonical_duplicate
(TypeErr.Bad_assignment
TypeErr.register_error analysis_data find_canonical_duplicate
(Bad_assignment
{ assignment_violation
; assignment_location= loc
; rhs_origin
; assignment_type=
AssignmentRule.ReportableViolation.PassingParamToFunction
PassingParamToFunction
{ param_signature= formal
; model_source= callee_annotated_signature.AnnotatedSignature.model_source
; actual_param_expression
; param_position
; function_procname= callee_pname } })
(Some instr_ref) ~nullsafe_mode loc curr_pdesc
(Some instr_ref) ~nullsafe_mode loc
in
if PatternMatch.type_is_class formal.param_annotated_type.typ then
(* Passing a param to a function is essentially an assignment the actual param value
@ -457,41 +458,42 @@ let check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv find_c
List.iter ~f:check resolved_params
let check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability
let check_inheritance_rule_for_return
({IntraproceduralAnalysis.proc_desc= overridden_proc_desc; _} as analysis_data)
find_canonical_duplicate loc ~nullsafe_mode ~base_proc_name ~base_nullability
~overridden_nullability =
Result.iter_error
(InheritanceRule.check InheritanceRule.Ret ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
register_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
TypeErr.register_error analysis_data find_canonical_duplicate
(Inconsistent_subclass
{ inheritance_violation
; violation_type= InheritanceRule.ReportableViolation.InconsistentReturn
; overridden_proc_name
; violation_type= InconsistentReturn
; overridden_proc_name= Procdesc.get_proc_name overridden_proc_desc
; base_proc_name })
None ~nullsafe_mode loc overridden_proc_desc )
None ~nullsafe_mode loc )
let check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode
~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc
let check_inheritance_rule_for_param
({IntraproceduralAnalysis.proc_desc= overridden_proc_desc; _} as analysis_data)
find_canonical_duplicate loc ~nullsafe_mode ~overridden_param_name ~base_proc_name
~param_position ~base_nullability ~overridden_nullability =
Result.iter_error
(InheritanceRule.check InheritanceRule.Param ~base:base_nullability
~overridden:overridden_nullability) ~f:(fun inheritance_violation ->
register_error tenv find_canonical_duplicate
(TypeErr.Inconsistent_subclass
TypeErr.register_error analysis_data find_canonical_duplicate
(Inconsistent_subclass
{ inheritance_violation
; violation_type=
InheritanceRule.ReportableViolation.InconsistentParam
InconsistentParam
{param_position; param_description= Mangled.to_string overridden_param_name}
; base_proc_name
; overridden_proc_name })
None ~nullsafe_mode loc overridden_proc_desc )
; overridden_proc_name= Procdesc.get_proc_name overridden_proc_desc })
None ~nullsafe_mode loc )
let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature
~overridden_signature =
let check_inheritance_rule_for_params analysis_data find_canonical_duplicate loc ~nullsafe_mode
~base_proc_name ~base_signature ~overridden_signature =
let base_params = base_signature.AnnotatedSignature.params in
let overridden_params = overridden_signature.AnnotatedSignature.params in
let zipped_params = List.zip base_params overridden_params in
@ -506,8 +508,8 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsaf
{ mangled= overridden_param_name
; param_annotated_type= {nullability= annotated_nullability_overridden} } )
->
check_inheritance_rule_for_param find_canonical_duplicate tenv loc ~nullsafe_mode
~overridden_param_name ~base_proc_name ~overridden_proc_name ~overridden_proc_desc
check_inheritance_rule_for_param analysis_data find_canonical_duplicate loc ~nullsafe_mode
~overridden_param_name ~base_proc_name
~param_position:(if should_index_from_zero then index else index + 1)
~base_nullability:(AnnotatedNullability.get_nullability annotated_nullability_base)
~overridden_nullability:
@ -518,13 +520,12 @@ let check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsaf
()
(* Check both params and return values for complying for co- and contravariance *)
let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_signature
~overridden_signature =
(** Check both params and return values for complying for co- and contravariance *)
let check_inheritance_rule_for_signature analysis_data find_canonical_duplicate loc ~nullsafe_mode
~base_proc_name ~base_signature ~overridden_signature =
(* Check params *)
check_inheritance_rule_for_params find_canonical_duplicate tenv loc ~nullsafe_mode ~base_proc_name
~overridden_proc_name ~overridden_proc_desc ~base_signature ~overridden_signature ;
check_inheritance_rule_for_params analysis_data find_canonical_duplicate loc ~nullsafe_mode
~base_proc_name ~base_signature ~overridden_signature ;
(* Check return value *)
match base_proc_name with
(* TODO model this as unknown nullability and get rid of that check *)
@ -538,9 +539,8 @@ let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~null
AnnotatedNullability.get_nullability
overridden_signature.AnnotatedSignature.ret.ret_annotated_type.nullability
in
check_inheritance_rule_for_return find_canonical_duplicate tenv loc ~nullsafe_mode
~base_proc_name ~overridden_proc_name ~overridden_proc_desc ~base_nullability
~overridden_nullability
check_inheritance_rule_for_return analysis_data find_canonical_duplicate loc ~nullsafe_mode
~base_proc_name ~base_nullability ~overridden_nullability
| _ ->
(* the analysis should not report return type inconsistencies with external code *)
()
@ -548,8 +548,8 @@ let check_inheritance_rule_for_signature find_canonical_duplicate tenv loc ~null
(** Checks if the annotations are consistent with the derived classes and with the implemented
interfaces *)
let check_overridden_annotations find_canonical_duplicate tenv proc_name proc_desc
annotated_signature =
let check_overridden_annotations ({IntraproceduralAnalysis.tenv; proc_desc; _} as analysis_data)
find_canonical_duplicate annotated_signature =
let start_node = Procdesc.get_start_node proc_desc in
let loc = Procdesc.Node.get_loc start_node in
let check_if_base_signature_matches_current base_proc_name =
@ -561,15 +561,16 @@ let check_overridden_annotations find_canonical_duplicate tenv proc_name proc_de
Models.get_modelled_annotated_signature ~is_callee_in_trust_list:false tenv
base_attributes
in
check_inheritance_rule_for_signature
check_inheritance_rule_for_signature analysis_data
~nullsafe_mode:annotated_signature.AnnotatedSignature.nullsafe_mode
find_canonical_duplicate tenv loc ~base_proc_name ~overridden_proc_name:proc_name
~overridden_proc_desc:proc_desc ~base_signature ~overridden_signature:annotated_signature
find_canonical_duplicate loc ~base_proc_name ~base_signature
~overridden_signature:annotated_signature
| None ->
(* Could not find the attributes - optimistically skipping the check *)
(* TODO(T54687014) ensure this is not an issue in practice *)
()
in
let proc_name = Procdesc.get_proc_name proc_desc in
(* Iterate over all methods the current method overrides and see the current
method is compatible with all of them *)
PatternMatch.override_iter check_if_base_signature_matches_current tenv proc_name

@ -9,7 +9,7 @@ open! IStd
(** Check an implicit cast when returning an immutable collection from a method whose type is
mutable. *)
let check_immutable_cast tenv curr_pname curr_pdesc typ_expected typ_found_opt loc : unit =
let check_immutable_cast analysis_data proc_desc typ_expected typ_found_opt loc : unit =
match typ_found_opt with
| Some typ_found -> (
let casts =
@ -32,16 +32,16 @@ let check_immutable_cast tenv curr_pname curr_pdesc typ_expected typ_found_opt l
Format.asprintf
"Method %s returns %a but the return type is %a. Make sure that users of this \
method do not try to modify the collection."
(Procname.to_simplified_string curr_pname)
(Procname.to_simplified_string (Procdesc.get_proc_name proc_desc))
Typ.Name.pp name_given Typ.Name.pp name_expected
in
EradicateCheckers.report_error tenv curr_pname curr_pdesc
IssueType.checkers_immutable_cast loc description ~severity:Exceptions.Warning
EradicateCheckers.report_error analysis_data IssueType.checkers_immutable_cast loc
description ~severity:Exceptions.Warning
| _ ->
() )
| None ->
()
let analyze ({IntraproceduralAnalysis.tenv} as analysis_data) =
Eradicate.analyze_for_immutable_cast_checker (check_immutable_cast tenv) analysis_data
let analyze analysis_data =
Eradicate.analyze_for_immutable_cast_checker (check_immutable_cast analysis_data) analysis_data

@ -104,15 +104,16 @@ end
(* ComplexExpressions *)
type check_return_type = Procname.t -> Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit
type check_return_type = Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit
type find_canonical_duplicate = Procdesc.Node.t -> Procdesc.Node.t
type checks = {eradicate: bool; check_ret_type: check_return_type list}
(** Typecheck an expression. *)
let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
(curr_pdesc : Procdesc.t) typestate e tr_default loc : TypeState.range =
let rec typecheck_expr ({IntraproceduralAnalysis.tenv; _} as analysis_data) ~nullsafe_mode
find_canonical_duplicate visited checks node instr_ref typestate e tr_default loc :
TypeState.range =
L.d_with_indent ~name:"typecheck_expr" ~pp_result:TypeState.pp_range (fun () ->
L.d_printfln "Expr: %a" Exp.pp e ;
match e with
@ -142,13 +143,13 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te
L.d_strln "WARNING: could not lookup Id in typestate: fallback to default" ;
tr_default )
| Exp.Exn e1 ->
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node instr_ref
curr_pdesc typestate e1 tr_default loc
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node
instr_ref typestate e1 tr_default loc
| Exp.Lfield (exp, field_name, typ) ->
let _, _ = tr_default in
let _, inferred_nullability =
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node
instr_ref curr_pdesc typestate exp
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node
instr_ref typestate exp
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(typ, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
@ -165,23 +166,22 @@ let rec typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks te
tr_default
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref exp
(DereferenceRule.ReportableViolation.AccessToField field_name) inferred_nullability
loc ;
EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode
find_canonical_duplicate node instr_ref exp (AccessToField field_name)
inferred_nullability loc ;
tr_new
| Exp.Lindex (array_exp, index_exp) ->
let _, inferred_nullability =
typecheck_expr ~nullsafe_mode find_canonical_duplicate visited checks tenv node
instr_ref curr_pdesc typestate array_exp tr_default loc
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate visited checks node
instr_ref typestate array_exp tr_default loc
in
let index_desc =
match EradicateChecks.explain_expr tenv node index_exp with Some s -> s | None -> "?"
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp
(DereferenceRule.ReportableViolation.AccessByIndex {index_desc})
EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode
find_canonical_duplicate node instr_ref array_exp
(AccessByIndex {index_desc})
inferred_nullability loc ;
let typ, _ = tr_default in
(typ, InferredNullability.create TypeOrigin.ArrayAccess)
@ -460,19 +460,19 @@ let pvar_apply instr_ref idenv tenv curr_pname curr_annotated_signature loc hand
(* typecheck_expr with fewer parameters, using a common template for typestate range *)
let typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv
let typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks
node instr_ref typestate1 exp1 typ1 origin1 loc1 =
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate1 exp1
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node
instr_ref typestate1 exp1
(typ1, InferredNullability.create origin1)
loc1
(* check if there are errors in exp1 *)
let typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate1 exp1 loc1 : unit =
let typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate1 exp1 loc1 : unit =
ignore
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks tenv
(typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks
node instr_ref typestate1 exp1 Typ.void TypeOrigin.OptimisticFallback loc1)
@ -498,9 +498,10 @@ let java_get_vararg_values node pvar idenv =
(* Handle Preconditions.checkNotNull. *)
let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc curr_pdesc
curr_pname curr_annotated_signature checks call_params idenv parameter_num ~is_vararg typestate'
=
let do_preconditions_check_not_null
({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) instr_ref
find_canonical_duplicate node loc curr_annotated_signature checks call_params idenv
parameter_num ~is_vararg typestate' =
(* clear the nullable flag of the first parameter of the procedure *)
let clear_nullable_flag ~nullsafe_mode typestate'' pvar =
(* remove the nullable flag for the given pvar *)
@ -514,12 +515,12 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node
in
( if checks.eradicate && should_report then
let cond = Exp.BinOp (Binop.Ne, Exp.Lvar pvar, Exp.null) in
EradicateChecks.register_error tenv find_canonical_duplicate
(TypeErr.Condition_redundant
TypeErr.register_error analysis_data find_canonical_duplicate
(Condition_redundant
{ is_always_true= true
; condition_descr= EradicateChecks.explain_expr tenv node cond
; nonnull_origin= InferredNullability.get_origin nullability })
(Some instr_ref) ~nullsafe_mode loc curr_pdesc ) ;
(Some instr_ref) ~nullsafe_mode loc ) ;
let previous_origin = InferredNullability.get_origin nullability in
let new_origin = TypeOrigin.InferredNonnull {previous_origin} in
TypeState.add pvar
@ -539,6 +540,7 @@ let do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node
in
match find_parameter parameter_num call_params with
| Some (pvar, _) ->
let curr_pname = Procdesc.get_proc_name curr_pdesc in
if is_vararg then
let do_vararg_value e ts =
match Idenv.expand_expr idenv e with
@ -626,8 +628,9 @@ let do_preconditions_check_state instr_ref idenv tenv curr_pname curr_annotated_
(* Handle m.put(k,v) as assignment pvar = v for the pvar associated to m.get(k) *)
let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks
instr_ref ~nullsafe_mode find_canonical_duplicate typestate' =
let do_map_put ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data)
call_params callee_pname loc node calls_this checks instr_ref ~nullsafe_mode
find_canonical_duplicate typestate' =
(* Get the proc name for map.get() from map.put() *)
let pname_get_from_pname_put pname_put =
let object_t = JavaSplitName.java_lang_object in
@ -656,11 +659,12 @@ let do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc call
ComplexExpressions.exp_to_string_map_dexp tenv convert_dexp_key_to_dexp_get node exp_key
with
| Some map_get_str ->
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let pvar_map_get = Pvar.mk (Mangled.from_string map_get_str) curr_pname in
TypeState.add pvar_map_get
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate' exp_value typ_value
TypeOrigin.OptimisticFallback loc)
(typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate' exp_value typ_value TypeOrigin.OptimisticFallback
loc)
typestate' ~descr:"do_map_put"
| None ->
typestate' )
@ -719,9 +723,11 @@ let normalize_cond_for_sil_prune idenv ~node cond =
normalize_cond_for_sil_prune_rec idenv ~node ~original_node:node cond
let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~nullsafe_mode ~original_node ~node c : TypeState.t =
let rec check_condition_for_sil_prune
({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data) idenv calls_this
find_canonical_duplicate loc curr_annotated_signature linereader typestate checks true_branch
instr_ref ~nullsafe_mode ~original_node ~node c : TypeState.t =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
(* check if the expression is coming from a call, and return the arguments *)
let extract_arguments_from_call filter_callee expr =
match expr with
@ -829,14 +835,14 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
This means the corresponding condition (initiated this PRUNE branch) was redudant.
*)
let typ, inferred_nullability =
typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv original_node instr_ref typestate pvar_expr Typ.void TypeOrigin.OptimisticFallback
typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks original_node instr_ref typestate pvar_expr Typ.void TypeOrigin.OptimisticFallback
loc
in
if checks.eradicate then
EradicateChecks.check_condition_for_redundancy ~is_always_true:true_branch tenv
find_canonical_duplicate curr_pdesc original_node pvar_expr typ inferred_nullability
~nullsafe_mode idenv linereader loc instr_ref ) ;
EradicateChecks.check_condition_for_redundancy analysis_data ~is_always_true:true_branch
find_canonical_duplicate original_node pvar_expr typ inferred_nullability ~nullsafe_mode
idenv linereader loc instr_ref ) ;
set_nonnull pvar_expr typestate ~descr
in
(* Assuming [expr] is a boolean, this is the branch where, according to PRUNE semantics,
@ -910,14 +916,14 @@ let rec check_condition_for_sil_prune tenv idenv calls_this find_canonical_dupli
*)
typestate |> handle_boolean_equal_true expr |> handle_object_not_equal_null expr
| Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Eq, e1, e2), _) ->
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~nullsafe_mode ~original_node ~node
check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc
curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode
~original_node ~node
(Exp.BinOp (Binop.Ne, e1, e2))
| Exp.UnOp (Unop.LNot, Exp.BinOp (Binop.Ne, e1, e2), _) ->
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~nullsafe_mode ~original_node ~node
check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc
curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode
~original_node ~node
(Exp.BinOp (Binop.Eq, e1, e2))
| _ ->
(* TODO(T54687014): silenced warning may be an unsoundeness issue; investigate *)
@ -949,15 +955,17 @@ let clarify_ret_by_propagates_nullable ret (resolved_params : EradicateChecks.re
(upper_bound_nullability, ret_typ)
let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref
signature_params cflags call_params ~is_anonymous_inner_class_constructor
~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java ~curr_pname
~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node =
let calc_typestate_after_call
({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data)
find_canonical_duplicate calls_this checks idenv instr_ref signature_params cflags call_params
~is_anonymous_inner_class_constructor ~callee_annotated_signature ~callee_attributes
~callee_pname ~callee_pname_java ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1
loc node =
let resolve_param i (formal_param, actual_param) =
let (orig_e2, e2), t2 = actual_param in
let _, inferred_nullability_actual =
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate e2
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node
instr_ref typestate e2
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(t2, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
@ -1011,34 +1019,35 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id
let typestate_after_call =
if not is_anonymous_inner_class_constructor then (
if cflags.CallFlags.cf_virtual && checks.eradicate then
EradicateChecks.check_call_receiver ~nullsafe_mode tenv find_canonical_duplicate curr_pdesc
EradicateChecks.check_call_receiver analysis_data ~nullsafe_mode find_canonical_duplicate
node typestate1 call_params callee_pname instr_ref loc
(typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks) ;
(typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks) ;
if checks.eradicate then
EradicateChecks.check_call_parameters ~nullsafe_mode ~callee_annotated_signature tenv
find_canonical_duplicate curr_pdesc node callee_attributes resolved_params loc instr_ref ;
EradicateChecks.check_call_parameters analysis_data ~nullsafe_mode
~callee_annotated_signature find_canonical_duplicate node callee_attributes
resolved_params loc instr_ref ;
if Models.is_check_not_null callee_pname then
match Models.get_check_not_null_parameter callee_pname with
| Some index ->
do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc
curr_pdesc curr_pname curr_annotated_signature checks call_params idenv index
~is_vararg:false typestate1
do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node
loc curr_annotated_signature checks call_params idenv index ~is_vararg:false
typestate1
| None when Procname.Java.is_vararg callee_pname_java ->
let last_parameter = List.length call_params in
do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc
curr_pdesc curr_pname curr_annotated_signature checks call_params idenv last_parameter
~is_vararg:true typestate1
do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node
loc curr_annotated_signature checks call_params idenv last_parameter ~is_vararg:true
typestate1
| None ->
(* assume the first parameter is checked for null *)
do_preconditions_check_not_null instr_ref tenv find_canonical_duplicate node loc
curr_pdesc curr_pname curr_annotated_signature checks call_params idenv 1
~is_vararg:false typestate1
do_preconditions_check_not_null analysis_data instr_ref find_canonical_duplicate node
loc curr_annotated_signature checks call_params idenv 1 ~is_vararg:false typestate1
else if Models.is_check_state callee_pname || Models.is_check_argument callee_pname then
let curr_pname = Procdesc.get_proc_name curr_pdesc in
do_preconditions_check_state instr_ref idenv tenv curr_pname curr_annotated_signature
call_params loc node typestate1
else if Models.is_mapPut callee_pname then
do_map_put call_params callee_pname tenv loc node curr_pname curr_pdesc calls_this checks
instr_ref ~nullsafe_mode find_canonical_duplicate typestate1
do_map_put analysis_data call_params callee_pname loc node calls_this checks instr_ref
~nullsafe_mode find_canonical_duplicate typestate1
else typestate1 )
else typestate1
in
@ -1046,9 +1055,10 @@ let calc_typestate_after_call find_canonical_duplicate calls_this checks tenv id
(* SIL instruction in form of [ret = fun(args);] where fun is a non-builtin Java function *)
let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode
ret_id_typ etl_ loc callee_pname_java cflags node =
let typecheck_sil_call_function
({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data)
find_canonical_duplicate checks instr_ref typestate idenv ~callee_pname curr_annotated_signature
calls_this ~nullsafe_mode ret_id_typ etl_ loc callee_pname_java cflags node =
L.d_with_indent ~name:"typecheck_sil_call_function" (fun () ->
let callee_attributes =
match PatternMatch.lookup_attributes tenv callee_pname with
@ -1074,11 +1084,12 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t
in
proc_attributes
in
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let etl = drop_unchecked_params calls_this curr_pname callee_attributes etl_ in
let call_params, typestate1 =
let handle_et (e1, t1) (etl1, typestate1) =
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e1 loc ;
typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate e1 loc ;
let e2 =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature
~is_assignment:false ~node ~original_node:node e1 typestate1 loc
@ -1124,19 +1135,19 @@ let typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref t
TypeState.add_id id (mk_return_range ()) typestate' ~descr:"typecheck_sil_call_function"
in
let typestate_after_call, finally_resolved_ret =
calc_typestate_after_call find_canonical_duplicate calls_this checks tenv idenv instr_ref
signature_params cflags call_params ~is_anonymous_inner_class_constructor
calc_typestate_after_call analysis_data find_canonical_duplicate calls_this checks idenv
instr_ref signature_params cflags call_params ~is_anonymous_inner_class_constructor
~callee_annotated_signature ~callee_attributes ~callee_pname ~callee_pname_java
~curr_pname ~curr_pdesc ~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1
loc node
~curr_annotated_signature ~nullsafe_mode ~typestate ~typestate1 loc node
in
do_return finally_resolved_ret typestate_after_call )
(** Typecheck an instruction. *)
let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_pname curr_pdesc
find_canonical_duplicate (curr_annotated_signature : AnnotatedSignature.t) instr_ref linereader
typestate instr =
let typecheck_instr ({IntraproceduralAnalysis.proc_desc= curr_pdesc; tenv; _} as analysis_data)
calls_this checks (node : Procdesc.Node.t) idenv find_canonical_duplicate
(curr_annotated_signature : AnnotatedSignature.t) instr_ref linereader typestate instr =
let curr_pname = Procdesc.get_proc_name curr_pdesc in
let is_return pvar =
let ret_pvar = Procdesc.get_ret_var curr_pdesc in
Pvar.equal pvar ret_pvar
@ -1153,22 +1164,22 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
| Sil.Metadata (Abstract _ | Nullify _ | Skip | VariableLifetimeBegins _) ->
typestate
| Sil.Load {id; e; typ; loc} ->
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e loc ;
typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate e loc ;
let e', typestate' =
convert_complex_exp_to_pvar_and_register_field_in_typestate tenv idenv curr_pname
curr_annotated_signature ~node ~original_node:node ~is_assignment:false e typestate loc
in
TypeState.add_id id
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate' e' typ TypeOrigin.OptimisticFallback loc)
(typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate' e' typ TypeOrigin.OptimisticFallback loc)
~descr:"Sil.Load" typestate'
| Sil.Store {e1= Exp.Lvar pvar; e2= Exp.Exn _} when is_return pvar ->
(* skip assignment to return variable where it is an artifact of a throw instruction *)
typestate
| Sil.Store {e1; typ; e2; loc} ->
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e1 loc ;
typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate e1 loc ;
let e1' =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature ~node
~original_node:node ~is_assignment:true e1 typestate loc
@ -1179,10 +1190,11 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
match AnnotatedField.get tenv field_name field_class_type with
| Some annotated_field ->
if checks.eradicate then
EradicateChecks.check_field_assignment ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref typestate ~expr_rhs:e2 ~field_type:typ loc field_name
annotated_field
(typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv)
EradicateChecks.check_field_assignment analysis_data ~nullsafe_mode
find_canonical_duplicate node instr_ref typestate ~expr_rhs:e2 ~field_type:typ loc
field_name annotated_field
(typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks)
| None ->
L.d_strln "WARNING: could not fetch field declaration; skipping assignment check" )
| _ ->
@ -1192,8 +1204,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
match e1' with
| Exp.Lvar pvar ->
TypeState.add pvar
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this
checks tenv node instr_ref typestate e2 typ TypeOrigin.OptimisticFallback loc)
(typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate
calls_this checks node instr_ref typestate e2 typ TypeOrigin.OptimisticFallback
loc)
typestate ~descr:"Sil.Store: Exp.Lvar case"
| Exp.Lfield _ ->
typestate
@ -1211,31 +1224,31 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
(* Type cast *)
| Sil.Call ((id, _), Exp.Const (Const.Cfun pn), (e, typ) :: _, loc, _)
when Procname.equal pn BuiltinDecl.__cast ->
typecheck_expr_for_errors ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e loc ;
typecheck_expr_for_errors analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate e loc ;
let e' =
convert_complex_exp_to_pvar tenv idenv curr_pname curr_annotated_signature
~is_assignment:false ~node ~original_node:node e typestate loc
in
(* cast copies the type of the first argument *)
TypeState.add_id id
(typecheck_expr_simple ~nullsafe_mode find_canonical_duplicate curr_pdesc calls_this checks
tenv node instr_ref typestate e' typ TypeOrigin.OptimisticFallback loc)
(typecheck_expr_simple analysis_data ~nullsafe_mode find_canonical_duplicate calls_this
checks node instr_ref typestate e' typ TypeOrigin.OptimisticFallback loc)
typestate ~descr:"type cast"
(* myarray.length *)
| Sil.Call ((id, _), Exp.Const (Const.Cfun pn), [(array_exp, t)], loc, _)
when Procname.equal pn BuiltinDecl.__get_array_length ->
let _, ta =
typecheck_expr ~nullsafe_mode find_canonical_duplicate calls_this checks tenv node instr_ref
curr_pdesc typestate array_exp
typecheck_expr analysis_data ~nullsafe_mode find_canonical_duplicate calls_this checks node
instr_ref typestate array_exp
(* TODO(T54687014) optimistic default might be an unsoundness issue - investigate *)
(t, InferredNullability.create TypeOrigin.OptimisticFallback)
loc
in
if checks.eradicate then
EradicateChecks.check_object_dereference ~nullsafe_mode tenv find_canonical_duplicate
curr_pdesc node instr_ref array_exp DereferenceRule.ReportableViolation.ArrayLengthAccess
ta loc ;
EradicateChecks.check_object_dereference analysis_data ~nullsafe_mode
find_canonical_duplicate node instr_ref array_exp
DereferenceRule.ReportableViolation.ArrayLengthAccess ta loc ;
TypeState.add_id id
(Typ.mk (Tint Typ.IInt), InferredNullability.create TypeOrigin.ArrayLengthResult)
typestate ~descr:"array.length"
@ -1249,9 +1262,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
, etl_
, loc
, cflags ) ->
typecheck_sil_call_function find_canonical_duplicate checks tenv instr_ref typestate idenv
~callee_pname ~curr_pname curr_pdesc curr_annotated_signature calls_this ~nullsafe_mode
ret_id_typ etl_ loc callee_pname_java cflags node
typecheck_sil_call_function analysis_data find_canonical_duplicate checks instr_ref typestate
idenv ~callee_pname curr_annotated_signature calls_this ~nullsafe_mode ret_id_typ etl_ loc
callee_pname_java cflags node
(* Calls instruction that is not a function call *)
| Sil.Call _ ->
(* This is something weird, we don't normally expect this type of instruction
@ -1261,9 +1274,9 @@ let typecheck_instr tenv calls_this checks (node : Procdesc.Node.t) idenv curr_p
typestate
| Sil.Prune (cond, loc, true_branch, _) ->
let node', normalized_cond = normalize_cond_for_sil_prune idenv ~node cond in
check_condition_for_sil_prune tenv idenv calls_this find_canonical_duplicate loc curr_pname
curr_pdesc curr_annotated_signature linereader typestate checks true_branch instr_ref
~nullsafe_mode ~node:node' ~original_node:node normalized_cond
check_condition_for_sil_prune analysis_data idenv calls_this find_canonical_duplicate loc
curr_annotated_signature linereader typestate checks true_branch instr_ref ~nullsafe_mode
~node:node' ~original_node:node normalized_cond
let can_instrunction_throw tenv node instr =
@ -1298,8 +1311,8 @@ let is_noreturn_instruction = function
(** Typecheck the instructions in a cfg node. *)
let typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc find_canonical_duplicate
annotated_signature typestate node linereader =
let typecheck_node ({IntraproceduralAnalysis.tenv; _} as analysis_data) calls_this checks idenv
find_canonical_duplicate annotated_signature typestate node linereader =
if Procdesc.Node.equal_nodekind (Procdesc.Node.get_kind node) Procdesc.Node.exn_sink_kind then
{normal_flow_typestate= None; exception_flow_typestates= []}
else
@ -1324,9 +1337,8 @@ let typecheck_node tenv calls_this checks idenv curr_pname curr_pdesc find_canon
TypeErr.InstrRef.gen instr_ref_gen
in
let normal_flow_typestate =
typecheck_instr tenv calls_this checks node idenv curr_pname curr_pdesc
find_canonical_duplicate annotated_signature instr_ref linereader
normal_flow_typestate_prev instr
typecheck_instr analysis_data calls_this checks node idenv find_canonical_duplicate
annotated_signature instr_ref linereader normal_flow_typestate_prev instr
in
if Config.write_html then
L.d_printfln "New state: @\n%a@\n" TypeState.pp normal_flow_typestate ;

@ -9,7 +9,7 @@ open! IStd
(** Module type for the type checking functions. *)
type check_return_type = Procname.t -> Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit
type check_return_type = Procdesc.t -> Typ.t -> Typ.t option -> Location.t -> unit
type find_canonical_duplicate = Procdesc.Node.t -> Procdesc.Node.t
@ -26,12 +26,10 @@ type typecheck_result =
together) will be passed to all "exception output" nodes of the current node. *) }
val typecheck_node :
Tenv.t
IntraproceduralAnalysis.t
-> bool ref
-> checks
-> Idenv.t
-> Procname.t
-> Procdesc.t
-> find_canonical_duplicate
-> AnnotatedSignature.t
-> TypeState.t

@ -169,17 +169,6 @@ let add_err find_canonical_duplicate err_instance instr_ref_opt loc =
not is_forall
type st_report_error =
Procname.t
-> Procdesc.t
-> IssueType.t
-> Location.t
-> ?field_name:Fieldname.t option
-> ?exception_kind:(IssueType.t -> Localise.error_desc -> exn)
-> severity:Exceptions.severity
-> string
-> unit
(* If an error is related to a particular field, we support suppressing the
error via a supress annotation placed near the field declaration *)
let get_field_name_for_error_suppressing = function
@ -338,37 +327,33 @@ let is_reportable ~nullsafe_mode err_instance =
get_error_info_fetcher_if_reportable ~nullsafe_mode err_instance |> Option.is_some
let report_now_if_reportable (st_report_error : st_report_error) err_instance ~nullsafe_mode loc
pdesc =
let pname = Procdesc.get_proc_name pdesc in
let report_now_if_reportable analysis_data err_instance ~nullsafe_mode loc =
get_error_info_if_reportable ~nullsafe_mode err_instance
|> Option.iter ~f:(fun (err_description, infer_issue_type, updated_location, severity) ->
Logging.debug Analysis Medium "About to report: %s" err_description ;
let field_name = get_field_name_for_error_suppressing err_instance in
let error_location = Option.value updated_location ~default:loc in
st_report_error pname pdesc infer_issue_type error_location ~field_name
EradicateCheckers.report_error analysis_data infer_issue_type error_location ~field_name
~exception_kind:(fun k d -> Exceptions.Eradicate (k, d))
~severity err_description )
(** Register issue (unless exactly the same issue was already registered). If needed, report this
error immediately. *)
let register_error (st_report_error : st_report_error) find_canonical_duplicate err_instance
~nullsafe_mode instr_ref_opt loc pdesc =
let register_error analysis_data find_canonical_duplicate err_instance ~nullsafe_mode instr_ref_opt
loc =
let should_report_now = add_err find_canonical_duplicate err_instance instr_ref_opt loc in
if should_report_now then
report_now_if_reportable st_report_error err_instance ~nullsafe_mode loc pdesc
if should_report_now then report_now_if_reportable analysis_data err_instance ~nullsafe_mode loc
let report_forall_issues_and_reset st_report_error ~nullsafe_mode proc_desc =
let report_forall_issues_and_reset analysis_data ~nullsafe_mode =
let iter (err_instance, instr_ref_opt) err_state =
match (instr_ref_opt, get_forall err_instance) with
| Some instr_ref, is_forall ->
let node = InstrRef.get_node instr_ref in
AnalysisState.set_node node ;
if is_forall && err_state.always then
report_now_if_reportable st_report_error err_instance err_state.loc ~nullsafe_mode
proc_desc
report_now_if_reportable analysis_data err_instance err_state.loc ~nullsafe_mode
| None, _ ->
()
in

@ -62,31 +62,19 @@ val pp_err_instance : Format.formatter -> err_instance -> unit
val node_reset_forall : Procdesc.Node.t -> unit
type st_report_error =
Procname.t
-> Procdesc.t
-> IssueType.t
-> Location.t
-> ?field_name:Fieldname.t option
-> ?exception_kind:(IssueType.t -> Localise.error_desc -> exn)
-> severity:Exceptions.severity
-> string
-> unit
val register_error :
st_report_error
IntraproceduralAnalysis.t
-> (Procdesc.Node.t -> Procdesc.Node.t)
-> err_instance
-> nullsafe_mode:NullsafeMode.t
-> InstrRef.t option
-> Location.t
-> Procdesc.t
-> unit
(** Register the fact that issue happened. Depending on the error and mode, this error might or
might not be reported to the user. *)
val report_forall_issues_and_reset :
st_report_error -> nullsafe_mode:NullsafeMode.t -> Procdesc.t -> unit
IntraproceduralAnalysis.t -> nullsafe_mode:NullsafeMode.t -> unit
(** Report registered "forall" issues (if needed), and reset the error table *)
val is_reportable : nullsafe_mode:NullsafeMode.t -> err_instance -> bool

Loading…
Cancel
Save