[pulse] Revise trace of uninitialized value check

Summary: This diff revises the trace generation of the uninitialized value checker, by introducing a new diagnostics for it.

Reviewed By: jvillard

Differential Revision: D25433775

fbshipit-source-id: 1279c0de4
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 0980bbe2b3
commit 3685cc6fdd

@ -325,25 +325,20 @@ let set_uninitialized_post src typ location (post : PostDomain.t) =
match typ.Typ.desc with match typ.Typ.desc with
| Tint _ | Tfloat _ | Tptr _ -> | Tint _ | Tfloat _ | Tptr _ ->
let {stack; attrs} = (post :> base_domain) in let {stack; attrs} = (post :> base_domain) in
let stack, addr, history = let stack, addr =
match src with match src with
| `LocalDecl (pvar, addr_opt) -> | `LocalDecl (pvar, addr_opt) -> (
let history = [ValueHistory.VariableDeclared (pvar, location)] in match addr_opt with
let stack, addr = | None ->
match addr_opt with let addr = AbstractValue.mk_fresh () in
| None -> let history = [ValueHistory.VariableDeclared (pvar, location)] in
let addr = AbstractValue.mk_fresh () in (BaseStack.add (Var.of_pvar pvar) (addr, history) stack, addr)
(BaseStack.add (Var.of_pvar pvar) (addr, history) stack, addr) | Some addr ->
| Some addr -> (stack, addr) )
(stack, addr) | `Malloc addr ->
in (stack, addr)
(stack, addr, history)
| `Malloc (addr, history) ->
(stack, addr, history)
in
let attrs =
BaseAddressAttributes.add_one addr (Uninitialized (Immediate {location; history})) attrs
in in
let attrs = BaseAddressAttributes.add_one addr Uninitialized attrs in
PostDomain.update ~stack ~attrs post PostDomain.update ~stack ~attrs post
| Tstruct _ -> | Tstruct _ ->
(* TODO: set uninitialized attributes for fields *) (* TODO: set uninitialized attributes for fields *)

@ -126,7 +126,7 @@ module AddressAttributes : sig
val check_valid : Trace.t -> AbstractValue.t -> t -> (t, Invalidation.t * Trace.t) result val check_valid : Trace.t -> AbstractValue.t -> t -> (t, Invalidation.t * Trace.t) result
val check_initialized : Trace.t -> AbstractValue.t -> t -> (t, Trace.t) result val check_initialized : Trace.t -> AbstractValue.t -> t -> (t, unit) result
val invalidate : AbstractValue.t * ValueHistory.t -> Invalidation.t -> Location.t -> t -> t val invalidate : AbstractValue.t * ValueHistory.t -> Invalidation.t -> Location.t -> t -> t
@ -188,8 +188,7 @@ val initialize : AbstractValue.t -> t -> t
val set_uninitialized : val set_uninitialized :
[ `LocalDecl of Pvar.t * AbstractValue.t option [ `LocalDecl of Pvar.t * AbstractValue.t option
(** the second optional parameter is for the address of the variable *) (** the second optional parameter is for the address of the variable *)
| `Malloc of AbstractValue.t * ValueHistory.t | `Malloc of AbstractValue.t (** the address parameter is a newly allocated address *) ]
(** the address parameter is a newly allocated address *) ]
-> Typ.t -> Typ.t
-> Location.t -> Location.t
-> t -> t

@ -35,7 +35,7 @@ module Attribute = struct
| MustBeInitialized of Trace.t | MustBeInitialized of Trace.t
| MustBeValid of Trace.t | MustBeValid of Trace.t
| StdVectorReserve | StdVectorReserve
| Uninitialized of Trace.t | Uninitialized
| WrittenTo of Trace.t | WrittenTo of Trace.t
[@@deriving compare, variants] [@@deriving compare, variants]
@ -72,7 +72,7 @@ module Attribute = struct
let end_of_collection_rank = Variants.to_rank EndOfCollection let end_of_collection_rank = Variants.to_rank EndOfCollection
let uninitialized_rank = Variants.to_rank (Uninitialized dummy_trace) let uninitialized_rank = Variants.to_rank Uninitialized
let must_be_initialized_rank = Variants.to_rank (MustBeInitialized dummy_trace) let must_be_initialized_rank = Variants.to_rank (MustBeInitialized dummy_trace)
@ -108,10 +108,8 @@ module Attribute = struct
F.fprintf f "MustBeValid %a" (Trace.pp ~pp_immediate:(pp_string_if_debug "access")) trace F.fprintf f "MustBeValid %a" (Trace.pp ~pp_immediate:(pp_string_if_debug "access")) trace
| StdVectorReserve -> | StdVectorReserve ->
F.pp_print_string f "std::vector::reserve()" F.pp_print_string f "std::vector::reserve()"
| Uninitialized trace -> | Uninitialized ->
F.fprintf f "Uninitialized %a" F.pp_print_string f "Uninitialized"
(Trace.pp ~pp_immediate:(pp_string_if_debug "declaration"))
trace
| WrittenTo trace -> | WrittenTo trace ->
F.fprintf f "WrittenTo %a" (Trace.pp ~pp_immediate:(pp_string_if_debug "mutation")) trace F.fprintf f "WrittenTo %a" (Trace.pp ~pp_immediate:(pp_string_if_debug "mutation")) trace
end end
@ -167,6 +165,8 @@ module Attributes = struct
|| Option.is_some (Set.find_rank attrs Attribute.invalid_rank) || Option.is_some (Set.find_rank attrs Attribute.invalid_rank)
let is_uninitialized attrs = Set.find_rank attrs Attribute.uninitialized_rank |> Option.is_some
let get_allocation attrs = let get_allocation attrs =
Set.find_rank attrs Attribute.allocated_rank Set.find_rank attrs Attribute.allocated_rank
|> Option.map ~f:(fun attr -> |> Option.map ~f:(fun attr ->
@ -181,13 +181,6 @@ module Attributes = struct
typ ) typ )
let get_uninitialized attrs =
Set.find_rank attrs Attribute.uninitialized_rank
|> Option.map ~f:(fun attr ->
let[@warning "-8"] (Attribute.Uninitialized trace) = attr in
trace )
let get_must_be_initialized attrs = let get_must_be_initialized attrs =
Set.find_rank attrs Attribute.must_be_initialized_rank Set.find_rank attrs Attribute.must_be_initialized_rank
|> Option.map ~f:(fun attr -> |> Option.map ~f:(fun attr ->
@ -211,7 +204,7 @@ let is_suitable_for_pre = function
| EndOfCollection | EndOfCollection
| Invalid _ | Invalid _
| StdVectorReserve | StdVectorReserve
| Uninitialized _ | Uninitialized
| WrittenTo _ -> | WrittenTo _ ->
false false
@ -223,8 +216,6 @@ let map_trace ~f = function
Invalid (invalidation, f trace) Invalid (invalidation, f trace)
| MustBeValid trace -> | MustBeValid trace ->
MustBeValid (f trace) MustBeValid (f trace)
| Uninitialized trace ->
Uninitialized (f trace)
| WrittenTo trace -> | WrittenTo trace ->
WrittenTo (f trace) WrittenTo (f trace)
| MustBeInitialized trace -> | MustBeInitialized trace ->
@ -234,5 +225,6 @@ let map_trace ~f = function
| Closure _ | Closure _
| DynamicType _ | DynamicType _
| EndOfCollection | EndOfCollection
| StdVectorReserve ) as attr -> | StdVectorReserve
| Uninitialized ) as attr ->
attr attr

@ -22,7 +22,7 @@ type t =
| MustBeInitialized of Trace.t | MustBeInitialized of Trace.t
| MustBeValid of Trace.t | MustBeValid of Trace.t
| StdVectorReserve | StdVectorReserve
| Uninitialized of Trace.t | Uninitialized
| WrittenTo of Trace.t | WrittenTo of Trace.t
[@@deriving compare] [@@deriving compare]
@ -56,7 +56,7 @@ module Attributes : sig
val is_std_vector_reserved : t -> bool val is_std_vector_reserved : t -> bool
val get_uninitialized : t -> Trace.t option val is_uninitialized : t -> bool
val get_must_be_initialized : t -> Trace.t option val get_must_be_initialized : t -> Trace.t option
end end

@ -87,11 +87,8 @@ let check_valid address attrs =
let check_initialized address attrs = let check_initialized address attrs =
L.d_printfln "Checking if %a is initialized" AbstractValue.pp address ; L.d_printfln "Checking if %a is initialized" AbstractValue.pp address ;
match Graph.find_opt address attrs |> Option.bind ~f:Attributes.get_uninitialized with if Graph.find_opt address attrs |> Option.exists ~f:Attributes.is_uninitialized then Error ()
| Some trace -> else Ok ()
Error trace
| None ->
Ok ()
let get_attribute getter address attrs = let get_attribute getter address attrs =
@ -108,11 +105,9 @@ let remove_allocation_attr address memory =
let initialize address attrs = let initialize address attrs =
match get_attribute Attributes.get_uninitialized address attrs with if Graph.find_opt address attrs |> Option.exists ~f:Attributes.is_uninitialized then
| Some trace -> remove_one address Attribute.Uninitialized attrs
remove_one address (Attribute.Uninitialized trace) attrs else attrs
| None ->
attrs
let get_closure_proc_name = get_attribute Attributes.get_closure_proc_name let get_closure_proc_name = get_attribute Attributes.get_closure_proc_name

@ -31,7 +31,7 @@ val fold : (AbstractValue.t -> Attributes.t -> 'a -> 'a) -> t -> 'a -> 'a
val check_valid : AbstractValue.t -> t -> (unit, Invalidation.t * Trace.t) result val check_valid : AbstractValue.t -> t -> (unit, Invalidation.t * Trace.t) result
val check_initialized : AbstractValue.t -> t -> (unit, Trace.t) result val check_initialized : AbstractValue.t -> t -> (unit, unit) result
val invalidate : AbstractValue.t * ValueHistory.t -> Invalidation.t -> Location.t -> t -> t val invalidate : AbstractValue.t * ValueHistory.t -> Invalidation.t -> Location.t -> t -> t

@ -19,23 +19,40 @@ type access_to_invalid_address =
; access_trace: Trace.t } ; access_trace: Trace.t }
[@@deriving equal] [@@deriving equal]
type read_uninitialized_value = {calling_context: (CallEvent.t * Location.t) list; trace: Trace.t}
[@@deriving equal]
let yojson_of_access_to_invalid_address = [%yojson_of: _] let yojson_of_access_to_invalid_address = [%yojson_of: _]
let yojson_of_read_uninitialized_value = [%yojson_of: _]
type t = type t =
| AccessToInvalidAddress of access_to_invalid_address | AccessToInvalidAddress of access_to_invalid_address
| MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t} | MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t}
| ReadUninitializedValue of read_uninitialized_value
| StackVariableAddressEscape of {variable: Var.t; history: ValueHistory.t; location: Location.t} | StackVariableAddressEscape of {variable: Var.t; history: ValueHistory.t; location: Location.t}
[@@deriving equal] [@@deriving equal]
let get_location = function let get_location = function
| AccessToInvalidAddress {calling_context= []; access_trace} -> | AccessToInvalidAddress {calling_context= []; access_trace}
| ReadUninitializedValue {calling_context= []; trace= access_trace} ->
Trace.get_outer_location access_trace Trace.get_outer_location access_trace
| AccessToInvalidAddress {calling_context= (_, location) :: _} -> | AccessToInvalidAddress {calling_context= (_, location) :: _}
| ReadUninitializedValue {calling_context= (_, location) :: _} ->
(* report at the call site that triggers the bug *) location (* report at the call site that triggers the bug *) location
| MemoryLeak {location} | StackVariableAddressEscape {location} -> | MemoryLeak {location} | StackVariableAddressEscape {location} ->
location location
(* 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
| [], Immediate _ ->
`Immediate
| (f, _) :: _, _ | [], ViaCall {f; _} ->
`Call f
let get_message = function let get_message = function
| AccessToInvalidAddress {calling_context; invalidation; invalidation_trace; access_trace} -> | AccessToInvalidAddress {calling_context; invalidation; invalidation_trace; access_trace} ->
(* The goal is to get one of the following messages depending on the scenario: (* The goal is to get one of the following messages depending on the scenario:
@ -55,14 +72,6 @@ let get_message = function
Likewise if we don't have "x" in the second part but instead some non-user-visible expression, then 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`" "`x->f` accesses `x`, which was invalidated at line 42 by `delete`"
*) *)
(* 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
| [], Immediate _ ->
`Immediate
| (f, _) :: _, _ | [], ViaCall {f; _} ->
`Call f
in
let pp_access_trace fmt (trace : Trace.t) = let pp_access_trace fmt (trace : Trace.t) =
match immediate_or_first_call calling_context trace with match immediate_or_first_call calling_context trace with
| `Immediate -> | `Immediate ->
@ -101,6 +110,16 @@ let get_message = function
F.asprintf F.asprintf
"memory dynamically allocated at line %d %a, is not freed after the last access at %a" "memory dynamically allocated at line %d %a, is not freed after the last access at %a"
allocation_line pp_allocation_trace allocation_trace Location.pp location allocation_line pp_allocation_trace allocation_trace Location.pp location
| ReadUninitializedValue {calling_context; trace} ->
let pp_trace fmt (trace : Trace.t) =
let {Location.line} = Trace.get_outer_location trace in
match immediate_or_first_call calling_context trace with
| `Immediate ->
F.fprintf fmt "on line %d" line
| `Call f ->
F.fprintf fmt "during the call to %a on line %d" CallEvent.describe f line
in
F.asprintf "uninitialized value is read %a" pp_trace trace
| StackVariableAddressEscape {variable; _} -> | StackVariableAddressEscape {variable; _} ->
let pp_var f var = let pp_var f var =
if Var.is_cpp_temporary var then F.pp_print_string f "C++ temporary" if Var.is_cpp_temporary var then F.pp_print_string f "C++ temporary"
@ -115,21 +134,24 @@ let add_errlog_header ~title location errlog =
Errlog.make_trace_element depth location title tags :: errlog Errlog.make_trace_element depth location title tags :: errlog
let get_trace_calling_context calling_context errlog =
match calling_context with
| [] ->
errlog
| (_, first_call_loc) :: _ ->
add_errlog_header ~title:"calling context starts here" first_call_loc
@@ ( List.fold calling_context ~init:(errlog, 0) ~f:(fun (errlog, depth) (call, loc) ->
( Errlog.make_trace_element depth loc
(F.asprintf "in call to %a" CallEvent.pp call)
[]
:: errlog
, depth + 1 ) )
|> fst )
let get_trace = function let get_trace = function
| AccessToInvalidAddress {calling_context; invalidation; invalidation_trace; access_trace} -> | AccessToInvalidAddress {calling_context; invalidation; invalidation_trace; access_trace} ->
(fun errlog -> get_trace_calling_context calling_context
match calling_context with
| [] ->
errlog
| (_, first_call_loc) :: _ ->
add_errlog_header ~title:"calling context starts here" first_call_loc
@@ ( List.fold calling_context ~init:(errlog, 0) ~f:(fun (errlog, depth) (call, loc) ->
( Errlog.make_trace_element depth loc
(F.asprintf "in call to %a" CallEvent.pp call)
[]
:: errlog
, depth + 1 ) )
|> fst ) )
@@ @@
let start_location = Trace.get_start_location invalidation_trace in let start_location = Trace.get_start_location invalidation_trace in
add_errlog_header ~title:"invalidation part of the trace starts here" start_location add_errlog_header ~title:"invalidation part of the trace starts here" start_location
@ -151,6 +173,12 @@ let get_trace = function
~pp_immediate:(fun fmt -> F.pp_print_string fmt "allocation part of the trace ends here") ~pp_immediate:(fun fmt -> F.pp_print_string fmt "allocation part of the trace ends here")
allocation_trace allocation_trace
@@ [Errlog.make_trace_element 0 location "memory becomes unreachable here" []] @@ [Errlog.make_trace_element 0 location "memory becomes unreachable here" []]
| ReadUninitializedValue {calling_context; trace} ->
get_trace_calling_context calling_context
@@ Trace.add_to_errlog ~nesting:0
~pp_immediate:(fun fmt -> F.pp_print_string fmt "read to uninitialized value occurs here")
trace
@@ []
| StackVariableAddressEscape {history; location; _} -> | StackVariableAddressEscape {history; location; _} ->
ValueHistory.add_to_errlog ~nesting:0 history ValueHistory.add_to_errlog ~nesting:0 history
@@ @@
@ -163,5 +191,7 @@ let get_issue_type = function
Invalidation.issue_type_of_cause invalidation Invalidation.issue_type_of_cause invalidation
| MemoryLeak _ -> | MemoryLeak _ ->
IssueType.pulse_memory_leak IssueType.pulse_memory_leak
| ReadUninitializedValue _ ->
IssueType.uninitialized_value_pulse
| StackVariableAddressEscape _ -> | StackVariableAddressEscape _ ->
IssueType.stack_variable_address_escape IssueType.stack_variable_address_escape

@ -24,10 +24,20 @@ type access_to_invalid_address =
invalidated in [invalidation_trace] without further assumptions *) } invalidated in [invalidation_trace] without further assumptions *) }
[@@deriving equal, yojson_of] [@@deriving equal, yojson_of]
type read_uninitialized_value =
{ calling_context: (CallEvent.t * Location.t) list
(** the list of function calls leading to the issue being realised, which is an additional
common prefix to the traces in the record *)
; trace: Trace.t
(** assuming we are in the calling context, the trace leads to read of the uninitialized
value *) }
[@@deriving equal, yojson_of]
(** an error to report to the user *) (** an error to report to the user *)
type t = type t =
| AccessToInvalidAddress of access_to_invalid_address | AccessToInvalidAddress of access_to_invalid_address
| MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t} | MemoryLeak of {procname: Procname.t; allocation_trace: Trace.t; location: Location.t}
| ReadUninitializedValue of read_uninitialized_value
| StackVariableAddressEscape of {variable: Var.t; history: ValueHistory.t; location: Location.t} | StackVariableAddressEscape of {variable: Var.t; history: ValueHistory.t; location: Location.t}
[@@deriving equal] [@@deriving equal]

@ -573,13 +573,9 @@ let check_all_valid callee_proc_name call_location {AbductiveDomain.pre; _} call
| Some callee_access_trace -> | Some callee_access_trace ->
let access_trace = mk_access_trace callee_access_trace in let access_trace = mk_access_trace callee_access_trace in
AddressAttributes.check_initialized access_trace addr_caller astate AddressAttributes.check_initialized access_trace addr_caller astate
|> Result.map_error ~f:(fun invalidation_trace -> |> Result.map_error ~f:(fun () ->
L.d_printfln "ERROR: caller's %a is uninitialized!" AbstractValue.pp addr_caller ; L.d_printfln "ERROR: caller's %a is uninitialized!" AbstractValue.pp addr_caller ;
( Diagnostic.AccessToInvalidAddress ( Diagnostic.ReadUninitializedValue {calling_context= []; trace= access_trace}
{ calling_context= []
; invalidation= Uninitialized
; invalidation_trace
; access_trace }
, astate ) ) ) , astate ) ) )
call_state.subst (Ok call_state.astate) call_state.subst (Ok call_state.astate)

@ -50,7 +50,6 @@ type t =
| OptionalEmpty | OptionalEmpty
| StdVector of std_vector_function | StdVector of std_vector_function
| JavaIterator of java_iterator_function | JavaIterator of java_iterator_function
| Uninitialized
[@@deriving compare, equal] [@@deriving compare, equal]
let issue_type_of_cause = function let issue_type_of_cause = function
@ -70,8 +69,6 @@ let issue_type_of_cause = function
IssueType.optional_empty_access IssueType.optional_empty_access
| JavaIterator _ | StdVector _ -> | JavaIterator _ | StdVector _ ->
IssueType.vector_invalidation IssueType.vector_invalidation
| Uninitialized ->
IssueType.uninitialized_value_pulse
let describe f cause = let describe f cause =
@ -99,8 +96,6 @@ let describe f cause =
F.fprintf f "was potentially invalidated by `%a()`" pp_std_vector_function std_vector_f F.fprintf f "was potentially invalidated by `%a()`" pp_std_vector_function std_vector_f
| JavaIterator java_iterator_f -> | JavaIterator java_iterator_f ->
F.fprintf f "was potentially invalidated by `%a()`" pp_java_iterator_function java_iterator_f F.fprintf f "was potentially invalidated by `%a()`" pp_java_iterator_function java_iterator_f
| Uninitialized ->
F.pp_print_string f "was uninitialized"
let pp f invalidation = let pp f invalidation =
@ -117,5 +112,3 @@ let pp f invalidation =
F.fprintf f "StdVector(%a)" describe invalidation F.fprintf f "StdVector(%a)" describe invalidation
| JavaIterator _ -> | JavaIterator _ ->
F.fprintf f "JavaIterator(%a)" describe invalidation F.fprintf f "JavaIterator(%a)" describe invalidation
| Uninitialized ->
F.pp_print_string f "Uninitialized"

@ -31,7 +31,6 @@ type t =
| OptionalEmpty | OptionalEmpty
| StdVector of std_vector_function | StdVector of std_vector_function
| JavaIterator of java_iterator_function | JavaIterator of java_iterator_function
| Uninitialized
[@@deriving compare, equal] [@@deriving compare, equal]
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit

@ -10,17 +10,23 @@ open PulseBasicInterface
module AbductiveDomain = PulseAbductiveDomain module AbductiveDomain = PulseAbductiveDomain
module Arithmetic = PulseArithmetic module Arithmetic = PulseArithmetic
type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address type t =
| AccessToInvalidAddress of Diagnostic.access_to_invalid_address
| ReadUninitializedValue of Diagnostic.read_uninitialized_value
[@@deriving equal, yojson_of] [@@deriving equal, yojson_of]
let to_diagnostic = function let to_diagnostic = function
| AccessToInvalidAddress access_to_invalid_address -> | AccessToInvalidAddress access_to_invalid_address ->
Diagnostic.AccessToInvalidAddress access_to_invalid_address Diagnostic.AccessToInvalidAddress access_to_invalid_address
| ReadUninitializedValue read_uninitialized_value ->
Diagnostic.ReadUninitializedValue read_uninitialized_value
let add_call call_and_loc = function let add_call call_and_loc = function
| AccessToInvalidAddress access -> | AccessToInvalidAddress access ->
AccessToInvalidAddress {access with calling_context= call_and_loc :: access.calling_context} AccessToInvalidAddress {access with calling_context= call_and_loc :: access.calling_context}
| ReadUninitializedValue read ->
ReadUninitializedValue {read with calling_context= call_and_loc :: read.calling_context}
let should_report (astate : AbductiveDomain.summary) = let should_report (astate : AbductiveDomain.summary) =
@ -37,3 +43,5 @@ let should_report_diagnostic (astate : AbductiveDomain.summary) (diagnostic : Di
`ReportNow `ReportNow
| AccessToInvalidAddress diag -> | AccessToInvalidAddress diag ->
if should_report astate then `ReportNow else `DelayReport (AccessToInvalidAddress diag) if should_report astate then `ReportNow else `DelayReport (AccessToInvalidAddress diag)
| ReadUninitializedValue diag ->
if should_report astate then `ReportNow else `DelayReport (ReadUninitializedValue diag)

@ -13,7 +13,9 @@ module AbductiveDomain = PulseAbductiveDomain
but we want to delay reporting until we see the conditions for the bug manifest themselves in but we want to delay reporting until we see the conditions for the bug manifest themselves in
some calling context. *) some calling context. *)
type t = AccessToInvalidAddress of Diagnostic.access_to_invalid_address type t =
| AccessToInvalidAddress of Diagnostic.access_to_invalid_address
| ReadUninitializedValue of Diagnostic.read_uninitialized_value
[@@deriving equal, yojson_of] [@@deriving equal, yojson_of]
val to_diagnostic : t -> Diagnostic.t val to_diagnostic : t -> Diagnostic.t

@ -152,7 +152,7 @@ module C = struct
let astate_alloc = let astate_alloc =
PulseArithmetic.and_positive ret_addr astate PulseArithmetic.and_positive ret_addr astate
|> PulseOperations.allocate callee_procname location ret_value |> PulseOperations.allocate callee_procname location ret_value
|> set_uninitialized size_exp_opt location ret_value |> set_uninitialized size_exp_opt location ret_addr
in in
let+ astate_null = let+ astate_null =
PulseArithmetic.and_eq_int ret_addr IntLit.zero astate PulseArithmetic.and_eq_int ret_addr IntLit.zero astate
@ -171,7 +171,7 @@ module C = struct
let astate = let astate =
PulseOperations.allocate callee_procname location ret_value astate PulseOperations.allocate callee_procname location ret_value astate
|> PulseArithmetic.and_positive ret_addr |> PulseArithmetic.and_positive ret_addr
|> set_uninitialized size_exp_opt location ret_value |> set_uninitialized size_exp_opt location ret_addr
in in
ok_continue astate ok_continue astate

@ -27,17 +27,9 @@ let check_addr_access access_mode location (address, history) astate =
in in
match access_mode with match access_mode with
| Read -> | Read ->
let+ astate = AddressAttributes.check_initialized access_trace address astate
AddressAttributes.check_initialized access_trace address astate |> Result.map_error ~f:(fun () ->
|> Result.map_error ~f:(fun invalidation_trace -> (Diagnostic.ReadUninitializedValue {calling_context= []; trace= access_trace}, astate) )
( Diagnostic.AccessToInvalidAddress
{ calling_context= []
; invalidation= Uninitialized
; invalidation_trace
; access_trace }
, astate ) )
in
astate
| Write -> | Write ->
Ok (AbductiveDomain.initialize address astate) Ok (AbductiveDomain.initialize address astate)
| NoAccess -> | NoAccess ->

@ -3,10 +3,10 @@ codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad2, 4, MEMORY_LE
codetoanalyze/c/pulse/memory_leak.c, malloc_no_free_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `malloc` (modelled),allocation part of the trace ends here,memory becomes unreachable here] codetoanalyze/c/pulse/memory_leak.c, malloc_no_free_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `malloc` (modelled),allocation part of the trace ends here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, malloc_no_check_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,allocated by call to `malloc` (modelled),is the null pointer,use-after-lifetime part of the trace starts here,allocated by call to `malloc` (modelled),assigned,invalid access occurs here] codetoanalyze/c/pulse/nullptr.c, malloc_no_check_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,allocated by call to `malloc` (modelled),is the null pointer,use-after-lifetime part of the trace starts here,allocated by call to `malloc` (modelled),assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, nullptr_deref_young_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here] codetoanalyze/c/pulse/nullptr.c, nullptr_deref_young_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here]
codetoanalyze/c/pulse/uninit.c, call_to_use_and_mayinit_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, call_to_use_and_mayinit_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, dereference_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `p` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `p` declared here,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, dereference_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `p` declared here,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, interprocedural_nop_in_callee_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, interprocedural_nop_in_callee_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, interprocedural_read_in_callee_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,when calling `read_int_ref` here,parameter `p` of read_int_ref,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, interprocedural_read_in_callee_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,when calling `read_int_ref` here,parameter `p` of read_int_ref,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, interprocedural_uninit_in_callee_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `uninit` here,allocated by call to `malloc` (modelled),was uninitialized,use-after-lifetime part of the trace starts here,passed as argument to `uninit`,return from call to `uninit`,assigned,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, interprocedural_uninit_in_callee_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [passed as argument to `uninit`,return from call to `uninit`,assigned,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, malloc_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,allocated by call to `malloc` (modelled),was uninitialized,use-after-lifetime part of the trace starts here,allocated by call to `malloc` (modelled),assigned,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, malloc_bad, 3, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [allocated by call to `malloc` (modelled),assigned,read to uninitialized value occurs here]
codetoanalyze/c/pulse/uninit.c, self_assign_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,invalid access occurs here] codetoanalyze/c/pulse/uninit.c, self_assign_bad, 2, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,read to uninitialized value occurs here]

@ -10,7 +10,7 @@ codetoanalyze/objc/pulse/MemoryLeaksInBlocks.m, block_captured_var_leak_bad, 6,
codetoanalyze/objc/pulse/NPEBlocks.m, Singleton.dispatch_once_no_npe_good_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here] codetoanalyze/objc/pulse/NPEBlocks.m, Singleton.dispatch_once_no_npe_good_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_3` here,parameter `x` of objc_blockcaptured_npe_bad_3,invalid access occurs here] codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,when calling `objc_blockcaptured_npe_bad_3` here,parameter `x` of objc_blockcaptured_npe_bad_3,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_ok_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here] codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_ok_FP, 6, NULLPTR_DEREFERENCE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,is the null pointer,use-after-lifetime part of the trace starts here,assigned,invalid access occurs here]
codetoanalyze/objc/pulse/uninit.m, Uninit.capture_in_closure_bad, 7, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,invalid access occurs here] codetoanalyze/objc/pulse/uninit.m, Uninit.capture_in_closure_bad, 7, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,read to uninitialized value occurs here]
codetoanalyze/objc/pulse/uninit.m, Uninit.not_set_in_closure_bad, 7, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `x` declared here,was uninitialized,use-after-lifetime part of the trace starts here,variable `x` declared here,invalid access occurs here] codetoanalyze/objc/pulse/uninit.m, Uninit.not_set_in_closure_bad, 7, PULSE_UNINITIALIZED_VALUE, no_bucket, ERROR, [variable `x` declared here,read to uninitialized value occurs here]
codetoanalyze/objc/pulse/use_after_free.m, PulseTest.use_after_free_simple_in_objc_method_bad:, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,invalid access occurs here] codetoanalyze/objc/pulse/use_after_free.m, PulseTest.use_after_free_simple_in_objc_method_bad:, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of PulseTest.use_after_free_simple_in_objc_method_bad:,invalid access occurs here]
codetoanalyze/objc/pulse/use_after_free.m, use_after_free_simple_bad, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of use_after_free_simple_bad,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of use_after_free_simple_bad,invalid access occurs here] codetoanalyze/objc/pulse/use_after_free.m, use_after_free_simple_bad, 2, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of use_after_free_simple_bad,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of use_after_free_simple_bad,invalid access occurs here]

Loading…
Cancel
Save