[pulse] report leaks as soon as values become unreachable

Summary:
This makes reports more readable: they were all at the end of functions,
currently.

This is actually quite tricky to do as it involves detecting which
locations are unreachable.

Some of this logic can/should probably be shared with
`AbductiveDomain.discard_unreachable` but at the moment that's not the
case.

Reviewed By: skcho

Differential Revision: D28382590

fbshipit-source-id: bd4239a0c
master
Jules Villard 4 years ago committed by Facebook GitHub Bot
parent d11852af9a
commit 99c53b2d7b

@ -647,6 +647,8 @@ module SafeInvertedMap (Key : PrettyPrintable.PrintableOrderedType) (ValueDomain
let of_seq = M.of_seq
let to_seq = M.to_seq
let mapi f m =
let tops = ref [] in
let f k v =

@ -0,0 +1,11 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
let fold_result seq ~init ~f =
Seq.fold_left (fun acc_result x -> Result.bind acc_result ~f:(fun acc -> f acc x)) (Ok init) seq

@ -0,0 +1,11 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
val fold_result :
'a Seq.t -> init:'accum -> f:('accum -> 'a -> ('accum, 'e) result) -> ('accum, 'e) result

@ -128,6 +128,8 @@ module type MonoMap = sig
val fold_mapi : t -> init:'a -> f:(key -> 'a -> value -> 'a * value) -> 'a * t
val of_seq : (key * value) Seq.t -> t
val to_seq : t -> (key * value) Seq.t
end
module type PPMap = sig

@ -130,6 +130,8 @@ module type MonoMap = sig
val fold_mapi : t -> init:'a -> f:(key -> 'a -> value -> 'a * value) -> 'a * t
val of_seq : (key * value) Seq.t -> t
val to_seq : t -> (key * value) Seq.t
end
module type PPMap = sig

@ -46,6 +46,8 @@ module type S = sig
val mem : t -> key -> bool
val union_left_biased : t -> t -> t
val to_seq : t -> (key * value) Seq.t
end
module Make
@ -139,14 +141,16 @@ module Make
else {count_new= next_count_new; new_= (key, value) :: new_without_key; old= map.old}
let fold map ~init ~f =
let acc = List.fold map.new_ ~init ~f in
(* this is quadratic time but the lists are at most [Config.limit] long, assumed small *)
List.fold map.old ~init:acc ~f:(fun acc binding ->
if List.Assoc.mem ~equal:Key.equal map.new_ (fst binding) then acc else f acc binding )
let to_seq map =
Seq.append (Caml.List.to_seq map.new_)
( (* this is quadratic time but the lists are at most [Config.limit] long, assumed small *)
Caml.List.to_seq map.old
|> Seq.filter (fun binding -> not (List.Assoc.mem ~equal:Key.equal map.new_ (fst binding))) )
let fold map ~init ~f = Seq.fold_left f init (to_seq map)
let bindings map = fold ~init:[] ~f:(fun bindings binding -> binding :: bindings) map
let bindings map = to_seq map |> Caml.List.of_seq
let exists map ~f =
List.exists map.new_ ~f

@ -49,6 +49,8 @@ module type S = sig
val mem : t -> key -> bool
val union_left_biased : t -> t -> t
val to_seq : t -> (key * value) Seq.t
end
module Make

@ -409,7 +409,8 @@ module PulseTransferFunctions = struct
| LatentInvalidAccess _ ->
[astate]
| ContinueProgram astate ->
[ContinueProgram (PulseOperations.remove_vars vars location astate)] )
PulseOperations.remove_vars vars location astate
|> PulseReport.report_result tenv proc_desc err_log location )
in
if Procname.is_java (Procdesc.get_proc_name proc_desc) then
remove_vars vars [ContinueProgram astate]

@ -273,6 +273,10 @@ module AddressAttributes = struct
map_post_attrs astate ~f:(BaseAddressAttributes.allocate procname address location)
let get_allocation addr astate =
BaseAddressAttributes.get_allocation addr (astate.post :> base_domain).attrs
let add_dynamic_type typ address astate =
map_post_attrs astate ~f:(BaseAddressAttributes.add_dynamic_type typ address)
@ -619,7 +623,7 @@ let check_memory_leaks unreachable_addrs astate =
addr Procname.pp procname ;
Error (procname, trace)
in
List.fold_result unreachable_addrs ~init:() ~f:(fun () addr ->
ISeq.fold_result unreachable_addrs ~init:() ~f:(fun () addr ->
match AddressAttributes.find_opt addr astate with
| Some unreachable_attrs ->
check_memory_leak addr unreachable_attrs
@ -950,7 +954,7 @@ let summary_of_post tenv pdesc location astate =
in
match error with
| None -> (
match check_memory_leaks dead_addresses astate_before_filter with
match check_memory_leaks (Caml.List.to_seq dead_addresses) astate_before_filter with
| Ok () ->
Ok (invalidate_locals pdesc astate)
| Error (proc_name, trace) ->

@ -132,6 +132,8 @@ module AddressAttributes : sig
val remove_allocation_attr : AbstractValue.t -> t -> t
val get_allocation : AbstractValue.t -> t -> (Procname.t * Trace.t) option
val get_closure_proc_name : AbstractValue.t -> t -> Procname.t option
val is_end_of_collection : AbstractValue.t -> t -> bool
@ -156,6 +158,10 @@ val is_local : Var.t -> t -> bool
val find_post_cell_opt : AbstractValue.t -> t -> BaseDomain.cell option
val check_memory_leaks : AbstractValue.t Seq.t -> t -> (unit, Procname.t * Trace.t) result
(** [check_memory_leaks unreachable_addrs astate] is an [Error (proc_name, trace)] if one of the
addresses in [unreachable_addrs] was allocated by [proc_name] *)
val discard_unreachable : t -> t
(** garbage collect unreachable addresses in the state to make it smaller and return the new state *)

@ -130,6 +130,8 @@ let initialize address attrs =
else attrs
let get_allocation = get_attribute Attributes.get_allocation
let get_closure_proc_name = get_attribute Attributes.get_closure_proc_name
let get_invalid = get_attribute Attributes.get_invalid

@ -35,6 +35,8 @@ val check_initialized : AbstractValue.t -> t -> (unit, unit) result
val invalidate : AbstractValue.t * ValueHistory.t -> Invalidation.t -> Location.t -> t -> t
val get_allocation : AbstractValue.t -> t -> (Procname.t * Trace.t) option
val get_closure_proc_name : AbstractValue.t -> t -> Procname.t option
val get_invalid : AbstractValue.t -> t -> (Invalidation.t * Trace.t) option

@ -205,7 +205,7 @@ module GraphVisit : sig
reached and the access path from that variable to the address. *)
val fold_from_addresses :
AbstractValue.t list
AbstractValue.t Seq.t
-> t
-> init:'accum
-> f:
@ -284,17 +284,14 @@ end = struct
let fold_from_addresses from astate =
fold_common from astate ~fold:List.fold ~filter:(fun _ -> true) ~visit:visit_address
let seq_fold seq ~init ~f = Seq.fold_left f init seq in
fold_common from astate ~fold:seq_fold ~filter:(fun _ -> true) ~visit:visit_address
end
include GraphComparison
let reachable_addresses astate =
GraphVisit.fold astate
~var_filter:(fun _ -> true)
~init:() ~finish:Fn.id
~f:(fun _ () _ _ -> Continue ())
|> fst
let reachable_addresses ?(var_filter = fun _ -> true) astate =
GraphVisit.fold astate ~var_filter ~init:() ~finish:Fn.id ~f:(fun _ () _ _ -> Continue ()) |> fst
let reachable_addresses_from addresses astate =

@ -7,6 +7,7 @@
open! IStd
open PulseBasicInterface
module Memory = PulseBaseMemory
module F = Format
type t = {heap: PulseBaseMemory.t; stack: PulseBaseStack.t; attrs: PulseBaseAddressAttributes.t}
@ -16,11 +17,11 @@ type cell = PulseBaseMemory.Edges.t * Attributes.t
val empty : t
val reachable_addresses : t -> AbstractValue.Set.t
val reachable_addresses : ?var_filter:(Var.t -> bool) -> t -> AbstractValue.Set.t
(** compute the set of abstract addresses that are "used" in the abstract state, i.e. reachable from
the stack variables *)
val reachable_addresses_from : AbstractValue.t list -> t -> AbstractValue.Set.t
val reachable_addresses_from : AbstractValue.t Seq.t -> t -> AbstractValue.Set.t
(** compute the set of abstract addresses that are reachable from given abstract addresses *)
type mapping
@ -40,3 +41,36 @@ val find_cell_opt : AbstractValue.t -> t -> cell option
val pp : F.formatter -> t -> unit
val subst_var : AbstractValue.t * AbstractValue.t -> t -> t SatUnsat.t
module GraphVisit : sig
val fold :
var_filter:(Var.t -> bool)
-> t
-> init:'accum
-> f:
( Var.t
-> 'accum
-> AbstractValue.t
-> Memory.Access.t list
-> ('accum, 'final) Base.Continue_or_stop.t)
-> finish:('accum -> 'final)
-> AbstractValue.Set.t * 'final
(** Generic graph traversal of the memory starting from each variable in the stack that pass
[var_filter], in order. Returns the result of folding over every address in the graph and the
set of addresses that have been visited before [f] returned [Stop] or all reachable addresses
were seen. [f] is passed each address together with the variable from which the address was
reached and the access path from that variable to the address. *)
val fold_from_addresses :
AbstractValue.t Seq.t
-> t
-> init:'accum
-> f:
( 'accum
-> AbstractValue.t
-> Memory.Access.t list
-> ('accum, 'final) Base.Continue_or_stop.t)
-> finish:('accum -> 'final)
-> AbstractValue.Set.t * 'final
(** Similar to [fold], but start from given addresses, instead of stack variables. *)
end

@ -188,7 +188,9 @@ let apply_callee tenv ~caller_proc_desc callee_pname call_loc callee_exec_state
let conservatively_initialize_args arg_values ({AbductiveDomain.post} as astate) =
let reachable_values = BaseDomain.reachable_addresses_from arg_values (post :> BaseDomain.t) in
let reachable_values =
BaseDomain.reachable_addresses_from (Caml.List.to_seq arg_values) (post :> BaseDomain.t)
in
AbstractValue.Set.fold AbductiveDomain.initialize reachable_values astate
@ -238,7 +240,6 @@ let call_aux tenv caller_proc_desc call_loc callee_pname ret actuals callee_proc
let call tenv ~caller_proc_desc ~(callee_data : (Procdesc.t * PulseSummary.t) option) call_loc
callee_pname ~ret ~actuals ~formals_opt (astate : AbductiveDomain.t) =
let get_arg_values () = List.map actuals ~f:(fun ((value, _), _) -> value) in
(* a special case for objc nil messaging *)
let unknown_objc_nil_messaging astate_unknown procdesc =
let result_unknown =
@ -267,8 +268,9 @@ let call tenv ~caller_proc_desc ~(callee_data : (Procdesc.t * PulseSummary.t) op
| None ->
(* no spec found for some reason (unknown function, ...) *)
L.d_printfln "No spec found for %a@\n" Procname.pp callee_pname ;
let arg_values = List.map actuals ~f:(fun ((value, _), _) -> value) in
let astate_unknown =
conservatively_initialize_args (get_arg_values ()) astate
conservatively_initialize_args arg_values astate
|> unknown_call tenv call_loc (SkippedKnownCall callee_pname) ~ret ~actuals ~formals_opt
in
let callee_procdesc_opt = AnalysisCallbacks.get_proc_desc callee_pname in

@ -570,9 +570,87 @@ let get_dynamic_type_unreachable_values vars astate =
List.map ~f:(fun (var, _, typ) -> (var, typ)) res
let remove_vars vars location orig_astate =
(** raised by [filter_live_addresses] to stop early when looking for leaks *)
exception NoLeak
let filter_live_addresses ~is_dead_root potential_leak_addrs astate =
(* stop as soon as we find out that all locations that could potentially cause a leak are still
live *)
if AbstractValue.Set.is_empty potential_leak_addrs then raise NoLeak ;
let potential_leaks = ref potential_leak_addrs in
let mark_reachable addr =
potential_leaks := AbstractValue.Set.remove addr !potential_leaks ;
if AbstractValue.Set.is_empty !potential_leaks then raise NoLeak
in
let pre = (astate.AbductiveDomain.pre :> BaseDomain.t) in
let post = (astate.AbductiveDomain.post :> BaseDomain.t) in
(* filter out addresses live in the post *)
ignore
(BaseDomain.GraphVisit.fold
~var_filter:(fun var -> not (is_dead_root var))
post ~init:()
~f:(fun _ () addr _ ->
mark_reachable addr ;
Continue () )
~finish:(fun () -> ())) ;
let collect_reachable_from addrs base_state =
BaseDomain.GraphVisit.fold_from_addresses addrs base_state ~init:()
~f:(fun () addr _ ->
mark_reachable addr ;
Continue () )
~finish:(fun () -> ())
|> fst
in
(* any address reachable in the pre-condition is not dead as callers can still be holding on to
them; so any address reachable from anything reachable from the precondition is live *)
let reachable_in_pre =
(* start from the *values* of variables, not their addresses; addresses of formals are
meaningless for callers so are not reachable outside the current function *)
let formal_values =
BaseStack.to_seq pre.stack
|> Seq.flat_map (fun (_, (formal_addr, _)) ->
match BaseMemory.find_opt formal_addr pre.heap with
| None ->
Seq.empty
| Some edges ->
BaseMemory.Edges.to_seq edges
|> Seq.map (fun (_access, (value, _)) ->
mark_reachable value ;
value ) )
in
collect_reachable_from formal_values pre
in
let reachable_from_reachable_in_pre =
collect_reachable_from (AbstractValue.Set.to_seq reachable_in_pre) post
in
ignore reachable_from_reachable_in_pre ;
!potential_leaks
let detect_leaks location ~dead_roots astate =
let is_dead_root var = List.mem ~equal:Var.equal dead_roots var in
(* only consider locations that could actually cause a leak if unreachable *)
let allocated_reachable_from_dead_root =
BaseDomain.reachable_addresses ~var_filter:is_dead_root
(astate.AbductiveDomain.post :> BaseDomain.t)
|> AbstractValue.Set.filter (fun addr ->
AddressAttributes.get_allocation addr astate |> Option.is_some )
in
match filter_live_addresses ~is_dead_root allocated_reachable_from_dead_root astate with
| exception NoLeak ->
Ok ()
| potential_leaks ->
AbductiveDomain.check_memory_leaks (AbstractValue.Set.to_seq potential_leaks) astate
|> Result.map_error ~f:(fun (procname, allocation_trace) ->
AccessResult.ReportableError
{astate; diagnostic= MemoryLeak {procname; allocation_trace; location}} )
let remove_vars vars location astate : t AccessResult.t =
let+ () = detect_leaks location ~dead_roots:vars astate in
(* remember addresses that will marked invalid later *)
let astate =
List.fold vars ~init:orig_astate ~f:(fun astate var ->
List.fold vars ~init:astate ~f:(fun astate var ->
match Stack.find_opt var astate with
| Some (address, history) ->
let astate =

@ -256,7 +256,7 @@ val get_dynamic_type_unreachable_values : Var.t list -> t -> (Var.t * Typ.t) lis
(** Given a list of variables, computes the unreachable values if the variables were removed from
the stack, then return the dynamic types of those values if they are available *)
val remove_vars : Var.t list -> Location.t -> t -> t
val remove_vars : Var.t list -> Location.t -> t -> t AccessResult.t
val check_address_escape :
Location.t -> Procdesc.t -> AbstractValue.t -> ValueHistory.t -> t -> t AccessResult.t

@ -8,28 +8,31 @@ codetoanalyze/c/pulse/interprocedural.c, if_freed_invalid_latent, 3, USE_AFTER_F
codetoanalyze/c/pulse/interprocedural.c, latent, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, make_latent_manifest, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [calling context starts here,in call to `propagate_latent_3_latent`,in call to `propagate_latent_2_latent`,in call to `propagate_latent_1_latent`,in call to `latent`,null pointer dereference part of the trace starts here,is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, test_modified_value_then_error_bad, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, trace_correctly_through_wrappers_bad, 5, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_wrapper_2` here,when calling `malloc_wrapper_1` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/interprocedural.c, trace_correctly_through_wrappers_bad, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_wrapper_2` here,when calling `malloc_wrapper_1` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/latent.c, FN_nonlatent_use_after_free_bad, 6, USE_AFTER_FREE, no_bucket, ERROR, [*** LATENT ***,invalidation part of the trace starts here,parameter `x` of FN_nonlatent_use_after_free_bad,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of FN_nonlatent_use_after_free_bad,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, latent_use_after_free, 4, 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 latent_use_after_free,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, latent_use_after_free, 4, USE_AFTER_FREE, no_bucket, ERROR, [*** LATENT ***,invalidation part of the trace starts here,parameter `x` of latent_use_after_free,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of latent_use_after_free,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, main, 3, USE_AFTER_FREE, no_bucket, ERROR, [calling context starts here,in call to `latent_use_after_free`,invalidation part of the trace starts here,parameter `x` of latent_use_after_free,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of latent_use_after_free,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, manifest_use_after_free, 0, USE_AFTER_FREE, no_bucket, ERROR, [calling context starts here,in call to `latent_use_after_free`,invalidation part of the trace starts here,parameter `x` of latent_use_after_free,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,parameter `x` of latent_use_after_free,invalid access occurs here]
codetoanalyze/c/pulse/memory_leak.c, alias_ptr_free_FP, 9, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, alias_ptr_free_FP, 10, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_formal_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `create_p` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad2, 5, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad2, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` 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 `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_out_parameter_local_mutation_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc_via_ptr`,is the null pointer,returned,return from call to `malloc_via_ptr`,assigned,invalid access occurs here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, report_leak_in_correct_line_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_after_abduction_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, bug_after_malloc_result_test_bad, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, bug_after_malloc_result_test_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_with_allocation_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_with_allocation_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, create_null_path2_latent, 8, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,assigned,is the null pointer,null pointer dereference part of the trace starts here,parameter `p` of create_null_path2_latent,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, malloc_no_check_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc` (modelled),is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, malloc_then_call_create_null_path_then_deref_unconditionally_latent, 7, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,in call to `malloc` (modelled),is the null pointer,null pointer dereference part of the trace starts here,parameter `p` of malloc_then_call_create_null_path_then_deref_unconditionally_latent,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc` (modelled),is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, nullptr_deref_young_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, user_malloc_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `a_malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/traces.c, access_null_deref_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]

@ -8,7 +8,7 @@ codetoanalyze/c/pulse/interprocedural.c, if_freed_invalid_latent, 3, USE_AFTER_F
codetoanalyze/c/pulse/interprocedural.c, latent, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, make_latent_manifest, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [calling context starts here,in call to `propagate_latent_3_latent`,in call to `propagate_latent_2_latent`,in call to `propagate_latent_1_latent`,in call to `latent`,null pointer dereference part of the trace starts here,is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, test_modified_value_then_error_bad, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/interprocedural.c, trace_correctly_through_wrappers_bad, 5, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_wrapper_2` here,when calling `malloc_wrapper_1` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/interprocedural.c, trace_correctly_through_wrappers_bad, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_wrapper_2` here,when calling `malloc_wrapper_1` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/latent.c, FN_nonlatent_use_after_free_bad, 6, USE_AFTER_FREE, no_bucket, ERROR, [*** LATENT ***,invalidation part of the trace starts here,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, latent_use_after_free, 4, 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,invalid access occurs here]
codetoanalyze/c/pulse/latent.c, latent_use_after_free, 4, USE_AFTER_FREE, no_bucket, ERROR, [*** LATENT ***,invalidation part of the trace starts here,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,invalid access occurs here]
@ -16,19 +16,22 @@ codetoanalyze/c/pulse/latent.c, main, 3, USE_AFTER_FREE, no_bucket, ERROR, [call
codetoanalyze/c/pulse/latent.c, manifest_use_after_free, 0, USE_AFTER_FREE, no_bucket, ERROR, [calling context starts here,in call to `latent_use_after_free`,invalidation part of the trace starts here,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,invalid access occurs here]
codetoanalyze/c/pulse/memory_leak.c, malloc_formal_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `create_p` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad2, 5, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_interproc_no_free_bad2, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` 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 `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_out_parameter_local_mutation_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc_via_ptr`,is the null pointer,returned,return from call to `malloc_via_ptr`,assigned,invalid access occurs here]
codetoanalyze/c/pulse/memory_leak.c, malloc_ptr_no_check_leak_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `malloc_via_ptr` here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/memory_leak.c, report_leak_in_correct_line_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_after_abduction_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, bug_after_malloc_result_test_bad, 4, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, bug_after_malloc_result_test_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_with_allocation_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, bug_with_allocation_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, create_null_path2_latent, 8, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,assigned,is the null pointer,null pointer dereference part of the trace starts here,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, malloc_no_check_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc` (modelled),is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, malloc_then_call_create_null_path_then_deref_unconditionally_latent, 7, NULLPTR_DEREFERENCE, no_bucket, ERROR, [*** LATENT ***,source of the null value part of the trace starts here,in call to `malloc` (modelled),is the null pointer,null pointer dereference part of the trace starts here,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 3, NULLPTR_DEREFERENCE, no_bucket, ERROR, [in call to `malloc` (modelled),is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, null_alias_bad, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/nullptr.c, nullptr_deref_young_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]
codetoanalyze/c/pulse/nullptr.c, user_malloc_leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `a_malloc` here,memory becomes unreachable here]
codetoanalyze/c/pulse/traces.c, access_null_deref_bad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]

@ -13,6 +13,18 @@ int* malloc_returned_ok() {
return p;
}
void malloc_out_parameter_ok(int** x) { *x = (int*)malloc(sizeof(int)); }
void malloc_out_parameter_local_mutation_ok(int** x) {
*x = (int*)malloc(sizeof(int));
x = NULL; // not visible from the outside
}
void malloc_out_parameter_local_mutation_bad(int** x) {
*x = (int*)malloc(sizeof(int));
*x = NULL;
}
void malloc_then_free_ok() {
int* p = malloc(sizeof(p));
if (p) {
@ -77,6 +89,15 @@ void alias_ptr_free_FP(int* out, int flag) {
} else {
y = out;
}
if (y && y != out)
if (y && y != out) {
free(y);
}
}
void report_leak_in_correct_line_bad(int* x) {
x = (int*)malloc(sizeof(int));
if (x != NULL) {
return; // should report leak at this line
}
free(x);
}

@ -1,12 +1,12 @@
codetoanalyze/objc/pulse/DeallocCalls.m, memory_leak_raii_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `BufferContainer2.init` here,allocated by `malloc_no_fail` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/DeallocCalls.m, memory_leak_raii_leak_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `BufferContainer2.init` here,allocated by `malloc_no_fail` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MallocInObjC.m, leak_bad, 0, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc_no_fail` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.call_no_bridge_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `MemoryLeaks.ret_no_bridge` here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.cg_path_create_mutable_leak_bad:, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CGPathCreateMutable` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.cg_path_create_with_rect_leak_bad, 4, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CGPathCreateWithRect` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.no_bridge_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, call_bridge_interproc_leak_ok_FP, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, call_cfrelease_interproc_leak_ok_FP, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaksInBlocks.m, block_captured_var_leak_bad, 7, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc_no_fail` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.call_no_bridge_leak_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,when calling `MemoryLeaks.ret_no_bridge` here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.cg_path_create_mutable_leak_bad:, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CGPathCreateMutable` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.cg_path_create_with_rect_leak_bad, 3, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CGPathCreateWithRect` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, MemoryLeaks.no_bridge_leak_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, call_bridge_interproc_leak_ok_FP, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaks.m, call_cfrelease_interproc_leak_ok_FP, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `CFLocaleCreate` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/MemoryLeaksInBlocks.m, block_captured_var_leak_bad, 6, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `malloc_no_fail` here,memory becomes unreachable here]
codetoanalyze/objc/pulse/NPEBlocks.m, Singleton.dispatch_once_captured_vars_bad, 8, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,in call to `objc_blockSingleton.dispatch_once_captured_vars_bad_2`,parameter `x` of objc_blockSingleton.dispatch_once_captured_vars_bad_2,assigned,return from call to `objc_blockSingleton.dispatch_once_captured_vars_bad_2`,invalid access occurs here]
codetoanalyze/objc/pulse/NPEBlocks.m, captured_npe_bad, 5, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,when calling `objc_blockcaptured_npe_bad_4` here,parameter `x` of objc_blockcaptured_npe_bad_4,invalid access occurs here]
codetoanalyze/objc/pulse/NPENilBlocks.m, BlockA.assignNilBad, 5, NIL_BLOCK_CALL, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here]

@ -1,4 +1,4 @@
codetoanalyze/objcpp/pulse/AllocPatternMemLeak.mm, A.create_no_release_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `ABFDataCreate` here,memory becomes unreachable here]
codetoanalyze/objcpp/pulse/AllocPatternMemLeak.mm, A.create_no_release_leak_bad, 1, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by `ABFDataCreate` here,memory becomes unreachable here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilInArrayBad, 0, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,in call to `NSMutableArray.addObject:` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilInDictBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,assigned,in call to `NSMutableDictionary.setObject:forKey:` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilKeyInDictBracketsBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,assigned,in call to `mutableDictionary[someKey] = value` (modelled),invalid access occurs here]

Loading…
Cancel
Save