diff --git a/infer/src/pulse/PulseDiagnostic.ml b/infer/src/pulse/PulseDiagnostic.ml index 892b06778..36b443b2c 100644 --- a/infer/src/pulse/PulseDiagnostic.ml +++ b/infer/src/pulse/PulseDiagnostic.ml @@ -45,6 +45,18 @@ let get_location = function location +let get_invalidation_in_trace trace = + PulseTrace.find_map trace ~f:(function + | ValueHistory.Invalidated (invalidation, _) -> + Some invalidation + | _ -> + None ) + + +let trace_contains_invalidation trace = + PulseTrace.exists trace ~f:(function ValueHistory.Invalidated _ -> true | _ -> false) + + (* whether the [calling_context + trace] starts with a call or contains only an immediate event *) let immediate_or_first_call calling_context (trace : Trace.t) = match (calling_context, trace) with @@ -58,73 +70,79 @@ let get_message diagnostic = let pulse_start_msg = "Pulse found a potential" in match diagnostic with | AccessToInvalidAddress {calling_context; invalidation; invalidation_trace; access_trace} -> ( - match invalidation with - | ConstantDereference i when IntLit.equal i IntLit.zero -> - (* Special error message for nullptr dereference *) - let pp_access_trace fmt (trace : Trace.t) = - match immediate_or_first_call calling_context trace with - | `Immediate -> - () - | `Call f -> - F.fprintf fmt " in call to %a" CallEvent.describe f - in - let pp_invalidation_trace line fmt (trace : Trace.t) = - let pp_line fmt line = F.fprintf fmt "on line %d" line in - match immediate_or_first_call calling_context trace with - | `Immediate -> - F.fprintf fmt "null pointer dereference %a" pp_line line - | `Call f -> - F.fprintf fmt "null pointer dereference %a indirectly during the call to %a" pp_line - line CallEvent.describe f - in - let invalidation_line = - let {Location.line; _} = Trace.get_outer_location invalidation_trace in - line - in - F.asprintf "%s %a%a." pulse_start_msg - (pp_invalidation_trace invalidation_line) - invalidation_trace pp_access_trace access_trace - | _ -> - (* The goal is to get one of the following messages depending on the scenario: + let invalidation, invalidation_trace = + get_invalidation_in_trace access_trace + |> Option.value_map + ~f:(fun invalidation -> (invalidation, access_trace)) + ~default:(invalidation, invalidation_trace) + in + match invalidation with + | ConstantDereference i when IntLit.equal i IntLit.zero -> + (* Special error message for nullptr dereference *) + let pp_access_trace fmt (trace : Trace.t) = + match immediate_or_first_call calling_context trace with + | `Immediate -> + () + | `Call f -> + F.fprintf fmt " in call to %a" CallEvent.describe f + in + let pp_invalidation_trace line fmt (trace : Trace.t) = + let pp_line fmt line = F.fprintf fmt "on line %d" line in + match immediate_or_first_call calling_context trace with + | `Immediate -> + F.fprintf fmt "null pointer dereference %a" pp_line line + | `Call f -> + F.fprintf fmt "null pointer dereference %a indirectly during the call to %a" pp_line + line CallEvent.describe f + in + let invalidation_line = + let {Location.line; _} = Trace.get_outer_location invalidation_trace in + line + in + F.asprintf "%s %a%a." pulse_start_msg + (pp_invalidation_trace invalidation_line) + invalidation_trace pp_access_trace access_trace + | _ -> + (* The goal is to get one of the following messages depending on the scenario: - 42: delete x; return x->f - "`x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x`" + 42: delete x; return x->f + "`x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x`" - 42: bar(x); return x->f - "`x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` in call to `bar`" + 42: bar(x); return x->f + "`x->f` accesses `x`, which was invalidated at line 42 by `delete` on `x` in call to `bar`" - 42: bar(x); foo(x); - "call to `foo` eventually accesses `x->f` but `x` was invalidated at line 42 by `delete` on `x` in call to `bar`" + 42: bar(x); foo(x); + "call to `foo` eventually accesses `x->f` but `x` was invalidated at line 42 by `delete` on `x` in call to `bar`" - If we don't have "x->f" but instead some non-user-visible expression, then - "access to `x`, which was invalidated at line 42 by `delete` on `x`" + If we don't have "x->f" but instead some non-user-visible expression, then + "access to `x`, which was invalidated at line 42 by `delete` on `x`" - Likewise if we don't have "x" in the second part but instead some non-user-visible expression, then - "`x->f` accesses `x`, which was invalidated at line 42 by `delete`" - *) - let pp_access_trace fmt (trace : Trace.t) = - match immediate_or_first_call calling_context trace with - | `Immediate -> - F.fprintf fmt "accessing memory that " - | `Call f -> - F.fprintf fmt "call to %a eventually accesses memory that " CallEvent.describe f - in - let pp_invalidation_trace line invalidation fmt (trace : Trace.t) = - let pp_line fmt line = F.fprintf fmt " on line %d" line in - match immediate_or_first_call calling_context trace with - | `Immediate -> - F.fprintf fmt "%a%a" Invalidation.describe invalidation pp_line line - | `Call f -> - F.fprintf fmt "%a%a indirectly during the call to %a" Invalidation.describe - invalidation pp_line line CallEvent.describe f - in - let invalidation_line = - let {Location.line; _} = Trace.get_outer_location invalidation_trace in - line - in - F.asprintf "%a%a" pp_access_trace access_trace - (pp_invalidation_trace invalidation_line invalidation) - invalidation_trace ) + Likewise if we don't have "x" in the second part but instead some non-user-visible expression, then + "`x->f` accesses `x`, which was invalidated at line 42 by `delete`" + *) + let pp_access_trace fmt (trace : Trace.t) = + match immediate_or_first_call calling_context trace with + | `Immediate -> + F.fprintf fmt "accessing memory that " + | `Call f -> + F.fprintf fmt "call to %a eventually accesses memory that " CallEvent.describe f + in + let pp_invalidation_trace line invalidation fmt (trace : Trace.t) = + let pp_line fmt line = F.fprintf fmt " on line %d" line in + match immediate_or_first_call calling_context trace with + | `Immediate -> + F.fprintf fmt "%a%a" Invalidation.describe invalidation pp_line line + | `Call f -> + F.fprintf fmt "%a%a indirectly during the call to %a" Invalidation.describe + invalidation pp_line line CallEvent.describe f + in + let invalidation_line = + let {Location.line; _} = Trace.get_outer_location invalidation_trace in + line + in + F.asprintf "%a%a" pp_access_trace access_trace + (pp_invalidation_trace invalidation_line invalidation) + invalidation_trace ) | MemoryLeak {procname; location; allocation_trace} -> let allocation_line = let {Location.line; _} = Trace.get_outer_location allocation_trace in @@ -212,10 +230,6 @@ let get_trace_calling_context calling_context errlog = |> fst ) -let trace_contains_invalidation trace = - PulseTrace.exists trace ~f:(function ValueHistory.Invalidated _ -> true | _ -> false) - - let add_invalidation_trace (invalidation : Invalidation.t) invalidation_trace access_trace errlog = let start_title, access_title = match invalidation with @@ -275,7 +289,10 @@ let get_trace = function let get_issue_type = function - | AccessToInvalidAddress {invalidation; must_be_valid_reason} -> + | AccessToInvalidAddress {invalidation; must_be_valid_reason; access_trace} -> + let invalidation = + get_invalidation_in_trace access_trace |> Option.value ~default:invalidation + in Invalidation.issue_type_of_cause invalidation must_be_valid_reason | MemoryLeak _ -> IssueType.pulse_memory_leak diff --git a/infer/src/pulse/PulseModels.ml b/infer/src/pulse/PulseModels.ml index 751b9e295..1ccca7490 100644 --- a/infer/src/pulse/PulseModels.ml +++ b/infer/src/pulse/PulseModels.ml @@ -312,7 +312,7 @@ module Optional = struct let<+> astate = PulseOperations.invalidate (MemoryAccess {pointer; access= Dereference; hist_obj_default= snd value}) - location Invalidation.OptionalEmpty value astate + location OptionalEmpty value astate in astate diff --git a/infer/src/pulse/PulseTrace.ml b/infer/src/pulse/PulseTrace.ml index 879303d1f..338ca5846 100644 --- a/infer/src/pulse/PulseTrace.ml +++ b/infer/src/pulse/PulseTrace.ml @@ -59,9 +59,9 @@ let rec add_to_errlog ?(include_value_history = true) ~nesting ~pp_immediate tra let rec iter trace ~f = match trace with | Immediate {history} -> - List.iter history ~f + ValueHistory.iter history ~f | ViaCall {history; in_call} -> - List.iter history ~f ; + ValueHistory.iter history ~f ; iter in_call ~f diff --git a/infer/src/pulse/PulseValueHistory.ml b/infer/src/pulse/PulseValueHistory.ml index aa3d55d5e..485c1c9a5 100644 --- a/infer/src/pulse/PulseValueHistory.ml +++ b/infer/src/pulse/PulseValueHistory.ml @@ -25,6 +25,26 @@ type event = and t = event list [@@deriving compare, equal] +let rec iter_event event ~f = + f event ; + match event with + | Call {in_call} -> + iter in_call ~f + | Allocation _ + | Assignment _ + | Capture _ + | Conditional _ + | CppTemporaryCreated _ + | FormalDeclared _ + | Invalidated _ + | StructFieldAddressCreated _ + | VariableAccessed _ + | VariableDeclared _ -> + () + + +and iter history ~f = List.iter history ~f:(fun event -> iter_event ~f event) + let yojson_of_event = [%yojson_of: _] let yojson_of_t = [%yojson_of: _] diff --git a/infer/src/pulse/PulseValueHistory.mli b/infer/src/pulse/PulseValueHistory.mli index 36087d781..62e075cf0 100644 --- a/infer/src/pulse/PulseValueHistory.mli +++ b/infer/src/pulse/PulseValueHistory.mli @@ -27,6 +27,9 @@ val pp : F.formatter -> t -> unit val pp_fields : F.formatter -> Fieldname.t RevList.t -> unit +val iter : t -> f:(event -> unit) -> unit +(** iterate on all events, recursing into the histories inside call events *) + val location_of_event : event -> Location.t val add_to_errlog : nesting:int -> t -> Errlog.loc_trace_elem list -> Errlog.loc_trace_elem list diff --git a/infer/tests/codetoanalyze/cpp/pulse/issues.exp b/infer/tests/codetoanalyze/cpp/pulse/issues.exp index 0dd961058..ce295eb88 100644 --- a/infer/tests/codetoanalyze/cpp/pulse/issues.exp +++ b/infer/tests/codetoanalyze/cpp/pulse/issues.exp @@ -64,13 +64,13 @@ codetoanalyze/cpp/pulse/nullptr.cpp, no_check_return_bad, 2, NULLPTR_DEREFERENCE codetoanalyze/cpp/pulse/nullptr.cpp, std_false_type_deref_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/cpp/pulse/nullptr.cpp, std_true_type_deref_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/cpp/pulse/nullptr.cpp, test_after_dereference2_latent, 1, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,is the null pointer,null pointer dereference part of the trace starts here,parameter `x` of test_after_dereference2_latent,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, FP_smart_pointer, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [source of the null value part of the trace starts here,when calling `Node::getShared` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `Node::getShared`,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,return from call to `Node::getShared`,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, FP_std_value_or_check_value_ok, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, FP_value_or_check_value_ok, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, assign2_bad, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `folly::Optional::operator=` here,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::operator=`,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,return from call to `folly::Optional::operator=`,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, FP_smart_pointer, 2, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `Node::getShared`,passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,return from call to `Node::getShared`,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, FP_std_value_or_check_value_ok, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, FP_value_or_check_value_ok, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, assign2_bad, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::operator=`,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,return from call to `folly::Optional::operator=`,invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, assign_bad, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,passed as argument to `folly::Optional::operator=`,parameter `other` of folly::Optional::operator=,passed as argument to `folly::Optional::assign(folly::Optional arg)` (modelled),return from call to `folly::Optional::assign(folly::Optional arg)` (modelled),return from call to `folly::Optional::operator=`,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, get_pointer_no_check_none_check_bad, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::get_pointer()` (modelled),return from call to `folly::Optional::get_pointer()` (modelled),is the null pointer,assigned,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, inside_try_catch_FP, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `might_return_none` here,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `might_return_none`,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,return from call to `might_return_none`,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, get_pointer_no_check_none_check_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [passed as argument to `folly::Optional::get_pointer()` (modelled),return from call to `folly::Optional::get_pointer()` (modelled),is the null pointer,assigned,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, inside_try_catch_FP, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `might_return_none`,passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,return from call to `might_return_none`,invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, none_copy_bad, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,passed as argument to `folly::Optional::Optional(folly::Optional arg)` (modelled),return from call to `folly::Optional::Optional(folly::Optional arg)` (modelled),invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, none_no_check_bad, 2, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, not_none_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::Optional(=None)` (modelled),return from call to `folly::Optional::Optional(=None)` (modelled),is optional empty,invalid access occurs here] @@ -79,7 +79,7 @@ codetoanalyze/cpp/pulse/optional.cpp, std_assign_bad, 5, OPTIONAL_EMPTY_ACCESS, codetoanalyze/cpp/pulse/optional.cpp, std_none_copy_bad, 3, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,passed as argument to `std::optional::optional(std::optional arg)` (modelled),return from call to `std::optional::optional(std::optional arg)` (modelled),invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, std_none_no_check_bad, 2, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,invalid access occurs here] codetoanalyze/cpp/pulse/optional.cpp, std_not_none_check_value_ok_FP, 5, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `std::optional::optional(=nullopt)` (modelled),return from call to `std::optional::optional(=nullopt)` (modelled),is optional empty,invalid access occurs here] -codetoanalyze/cpp/pulse/optional.cpp, test_trace_ref, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `folly::Optional::operator=` here,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,use-after-lifetime part of the trace starts here,passed as argument to `folly::Optional::operator=`,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,return from call to `folly::Optional::operator=`,invalid access occurs here] +codetoanalyze/cpp/pulse/optional.cpp, test_trace_ref, 4, OPTIONAL_EMPTY_ACCESS, no_bucket, ERROR, [passed as argument to `folly::Optional::operator=`,passed as argument to `folly::Optional::reset()` (modelled),return from call to `folly::Optional::reset()` (modelled),is optional empty,return from call to `folly::Optional::operator=`,invalid access occurs here] codetoanalyze/cpp/pulse/path.cpp, faulty_call_bad, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [calling context starts here,in call to `only_bad_on_42_latent`,source of the null value part of the trace starts here,when calling `may_return_null` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `may_return_null`,return from call to `may_return_null`,assigned,invalid access occurs here] codetoanalyze/cpp/pulse/path.cpp, only_bad_on_42_latent, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,when calling `may_return_null` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `may_return_null`,return from call to `may_return_null`,assigned,invalid access occurs here] codetoanalyze/cpp/pulse/reference_wrapper.cpp, reference_wrapper_heap_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `getwrapperHeap` here,passed as argument to `WrapsB::WrapsB`,passed as argument to `new` (modelled),return from call to `new` (modelled),assigned,return from call to `WrapsB::WrapsB`,when calling `WrapsB::~WrapsB` here,parameter `this` of WrapsB::~WrapsB,when calling `WrapsB::__infer_inner_destructor_~WrapsB` here,parameter `this` of WrapsB::__infer_inner_destructor_~WrapsB,was invalidated by `delete`,use-after-lifetime part of the trace starts here,passed as argument to `getwrapperHeap`,passed as argument to `WrapsB::WrapsB`,passed as argument to `new` (modelled),return from call to `new` (modelled),assigned,return from call to `WrapsB::WrapsB`,passed as argument to `ReferenceWrapperHeap::ReferenceWrapperHeap`,parameter `a` of ReferenceWrapperHeap::ReferenceWrapperHeap,passed as argument to `WrapsB::getb`,return from call to `WrapsB::getb`,assigned,return from call to `ReferenceWrapperHeap::ReferenceWrapperHeap`,return from call to `getwrapperHeap`,invalid access occurs here] diff --git a/infer/tests/codetoanalyze/java/pulse/issues.exp b/infer/tests/codetoanalyze/java/pulse/issues.exp index f11efe8b1..27e4aa30b 100644 --- a/infer/tests/codetoanalyze/java/pulse/issues.exp +++ b/infer/tests/codetoanalyze/java/pulse/issues.exp @@ -4,7 +4,6 @@ codetoanalyze/java/pulse/AnalysisStops.java, codetoanalyze.java.infer.AnalysisSt codetoanalyze/java/pulse/Builtins.java, codetoanalyze.java.infer.Builtins.FP_blockErrorIntAssumeOk(java.lang.Object):void, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/Builtins.java, codetoanalyze.java.infer.Builtins.FP_blockErrorOk():void, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/Builtins.java, codetoanalyze.java.infer.Builtins.doNotBlockErrorBad(java.lang.Object):void, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,invalid access occurs here] -codetoanalyze/java/pulse/Builtins.java, codetoanalyze.java.infer.Builtins.doNotBlockErrorBad(java.lang.Object):void, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/DefaultInInterface.java, DefaultInInterface$A.defaultCallNPE():void, 1, NULLPTR_DEREFERENCE, no_bucket, ERROR, [source of the null value part of the trace starts here,when calling `Object DefaultInInterface$I.defaultMethod1()` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `Object DefaultInInterface$I.defaultMethod1()`,return from call to `Object DefaultInInterface$I.defaultMethod1()`,assigned,invalid access occurs here] codetoanalyze/java/pulse/DefaultInInterface.java, DefaultInInterface$B.overridenCallNPE():void, 1, NULLPTR_DEREFERENCE, no_bucket, ERROR, [source of the null value part of the trace starts here,when calling `Object DefaultInInterface$B.defaultMethod2()` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `Object DefaultInInterface$B.defaultMethod2()`,return from call to `Object DefaultInInterface$B.defaultMethod2()`,assigned,invalid access occurs here] codetoanalyze/java/pulse/DefaultInInterface.java, DefaultInInterface.uncertainCallMethod1NPE_latent(int):void, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,when calling `Object DefaultInInterface$I.defaultMethod1()` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `Object DefaultInInterface$I.defaultMethod1()`,return from call to `Object DefaultInInterface$I.defaultMethod1()`,assigned,invalid access occurs here] @@ -64,7 +63,7 @@ codetoanalyze/java/pulse/NullPointerExceptions.java, codetoanalyze.java.infer.Nu codetoanalyze/java/pulse/NullPointerExceptions.java, codetoanalyze.java.infer.NullPointerExceptions.someNPEAfterResourceLeak():void, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [source of the null value part of the trace starts here,when calling `T CloseableAsResourceExample.sourceOfNullWithResourceLeak()` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `T CloseableAsResourceExample.sourceOfNullWithResourceLeak()`,return from call to `T CloseableAsResourceExample.sourceOfNullWithResourceLeak()`,assigned,invalid access occurs here] codetoanalyze/java/pulse/NullPointerExceptions.java, codetoanalyze.java.infer.NullPointerExceptions.stringConstantEqualsFalseNotNPE_FP():void, 10, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/NullPointerExceptions.java, codetoanalyze.java.infer.NullPointerExceptions.stringVarEqualsFalseNPE():void, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] -codetoanalyze/java/pulse/NullSafeExample.java, OtherClass.buggyMethodBad():java.lang.String, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [source of the null value part of the trace starts here,when calling `OtherClass.()` here,assigned,is the null pointer,null pointer dereference part of the trace starts here,passed as argument to `OtherClass.()`,is the null pointer,assigned,return from call to `OtherClass.()`,passed as argument to `OtherClass OtherClass.canReturnNull()`,return from call to `OtherClass OtherClass.canReturnNull()`,assigned,invalid access occurs here] +codetoanalyze/java/pulse/NullSafeExample.java, OtherClass.buggyMethodBad():java.lang.String, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [passed as argument to `OtherClass.()`,is the null pointer,assigned,return from call to `OtherClass.()`,passed as argument to `OtherClass OtherClass.canReturnNull()`,return from call to `OtherClass OtherClass.canReturnNull()`,assigned,invalid access occurs here] codetoanalyze/java/pulse/PreconditionsExample.java, codetoanalyze.java.infer.PreconditionsExample.checkArgumentSatBad():void, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/PreconditionsExample.java, codetoanalyze.java.infer.PreconditionsExample.checkStateConditionSatBad():void, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/java/pulse/PreconditionsExample.java, codetoanalyze.java.infer.PreconditionsExample.testCheckNotNullArgLatent(java.lang.Object):void, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,invalid access occurs here]