[pulse] abduce arithmetic facts

Summary:
This does several things because it was hard to split it more:
1. Split most of the arithmetic reasoning to PulseArithmetic.ml. This
doesn't need to be reviewed thoroughly because an upcoming diff
changes the domain from just `EqualTo of Const.t` to an interval domain!
2. When going through a prune node intra-procedurally, abduce arithmetic
facts to the pre (instead of just propagating them). This is the "assume
as assert" trick used by biabduction 1.0 too and allows to propagate
arithmetic constraints to callers.
3. Use 2 when applying summaries by pruning specs whose preconditions
have un-satisfiable arithmetic constraints.

This changes one of the tests! Pulse now does a bit more work to find
the false positive, as can be seen in the longer trace.

Reviewed By: skcho

Differential Revision: D18117160

fbshipit-source-id: af3b2c8c0
master
Jules Villard 5 years ago committed by Facebook Github Bot
parent 702602dcec
commit b20c22a5ee

@ -214,7 +214,7 @@ module Memory = struct
BaseMemory.get_closure_proc_name addr (astate.post :> base_domain).heap BaseMemory.get_closure_proc_name addr (astate.post :> base_domain).heap
let get_constant addr astate = BaseMemory.get_constant addr (astate.post :> base_domain).heap let get_arithmetic addr astate = BaseMemory.get_arithmetic addr (astate.post :> base_domain).heap
let std_vector_reserve addr astate = let std_vector_reserve addr astate =
map_post_heap astate ~f:(fun heap -> BaseMemory.std_vector_reserve addr heap) map_post_heap astate ~f:(fun heap -> BaseMemory.std_vector_reserve addr heap)
@ -347,10 +347,35 @@ module PrePost = struct
module AddressSet = AbstractValue.Set module AddressSet = AbstractValue.Set
module AddressMap = AbstractValue.Map module AddressMap = AbstractValue.Map
(** raised when the pre/post pair and the current state disagree on the aliasing, i.e. some type cannot_apply_pre =
addresses that are distinct in the pre/post are aliased in the current state. Typically raised | Aliasing of
when calling [foo(z,z)] where the spec for [foo(x,y)] says that [x] and [y] are disjoint. *) { addr_caller: AbstractValue.t
exception Aliasing ; addr_callee: AbstractValue.t
; addr_callee': AbstractValue.t }
(** raised when the precondition and the current state disagree on the aliasing, i.e. some
addresses [callee_addr] and [callee_addr'] that are distinct in the pre are aliased to
a single address [caller_addr] in the caller's current state. Typically raised when
calling [foo(z,z)] where the spec for [foo(x,y)] says that [x] and [y] are disjoint. *)
| Arithmetic of
{ addr_caller: AbstractValue.t
; addr_callee: AbstractValue.t
; arith_caller: Arithmetic.t option
; arith_callee: Arithmetic.t option }
(** raised when the pre asserts arithmetic facts that are demonstrably false in the caller
state *)
let pp_cannot_apply_pre fmt = function
| Aliasing {addr_caller; addr_callee; addr_callee'} ->
F.fprintf fmt "address %a in caller already bound to %a, not %a" AbstractValue.pp
addr_caller AbstractValue.pp addr_callee' AbstractValue.pp addr_callee
| Arithmetic {addr_caller; addr_callee; arith_caller; arith_callee} ->
F.fprintf fmt "caller addr %a%a but callee addr %a%a; %a=%a is unsatisfiable"
AbstractValue.pp addr_caller (Pp.option Arithmetic.pp) arith_caller AbstractValue.pp
addr_callee (Pp.option Arithmetic.pp) arith_callee AbstractValue.pp addr_caller
AbstractValue.pp addr_callee
exception CannotApplyPre of cannot_apply_pre
(** stuff we carry around when computing the result of applying one pre/post pair *) (** stuff we carry around when computing the result of applying one pre/post pair *)
type call_state = type call_state =
@ -399,10 +424,7 @@ module PrePost = struct
let addr_caller = fst addr_hist_caller in let addr_caller = fst addr_hist_caller in
( match AddressMap.find_opt addr_caller call_state.rev_subst with ( match AddressMap.find_opt addr_caller call_state.rev_subst with
| Some addr_callee' when not (AbstractValue.equal addr_callee addr_callee') -> | Some addr_callee' when not (AbstractValue.equal addr_callee addr_callee') ->
L.d_printfln "Huho, address %a in post already bound to %a, not %a@\nState=%a" raise (CannotApplyPre (Aliasing {addr_caller; addr_callee; addr_callee'}))
AbstractValue.pp addr_caller AbstractValue.pp addr_callee' AbstractValue.pp addr_callee
pp_call_state call_state ;
raise Aliasing
| _ -> | _ ->
() ) ; () ) ;
if AddressSet.mem addr_callee call_state.visited then (`AlreadyVisited, call_state) if AddressSet.mem addr_callee call_state.visited then (`AlreadyVisited, call_state)
@ -421,6 +443,32 @@ module PrePost = struct
(* {3 reading the pre from the current state} *) (* {3 reading the pre from the current state} *)
let solve_arithmetic_constraints ~addr_pre ~attrs_pre ~addr_hist_caller call_state =
match Attributes.get_arithmetic attrs_pre with
| None ->
call_state
| Some _ as arith_callee ->
let addr_caller = fst addr_hist_caller in
let astate = call_state.astate in
let arith_caller = Memory.get_arithmetic addr_caller astate in
(* TODO: we don't use [abduced_callee] but we could probably use it to refine the attributes
for that address in the post since abstract values are immutable *)
let satisfiable, abduce_caller, _abduce_callee =
Arithmetic.abduce_binop_is_true ~negated:false Eq arith_caller arith_callee
in
if not satisfiable then
raise
(CannotApplyPre
(Arithmetic {addr_caller; addr_callee= addr_pre; arith_caller; arith_callee})) ;
let new_astate =
Option.fold abduce_caller ~init:astate ~f:(fun astate abduce_caller ->
let attribute = Attribute.Arithmetic abduce_caller in
Memory.abduce_attribute addr_caller attribute astate
|> Memory.add_attribute addr_caller attribute )
in
{call_state with astate= new_astate}
(** Materialize the (abstract memory) subgraph of [pre] reachable from [addr_pre] in (** Materialize the (abstract memory) subgraph of [pre] reachable from [addr_pre] in
[call_state.astate] starting from address [addr_caller]. Report an error if some invalid [call_state.astate] starting from address [addr_caller]. Report an error if some invalid
addresses are traversed in the process. *) addresses are traversed in the process. *)
@ -433,7 +481,10 @@ module PrePost = struct
match BaseMemory.find_opt addr_pre pre.BaseDomain.heap with match BaseMemory.find_opt addr_pre pre.BaseDomain.heap with
| None -> | None ->
Ok call_state Ok call_state
| Some (edges_pre, _attrs_pre) -> | Some (edges_pre, attrs_pre) ->
let call_state =
solve_arithmetic_constraints ~addr_pre ~attrs_pre ~addr_hist_caller call_state
in
Container.fold_result Container.fold_result
~fold:(IContainer.fold_of_pervasives_map_fold ~fold:Memory.Edges.fold) ~fold:(IContainer.fold_of_pervasives_map_fold ~fold:Memory.Edges.fold)
~init:call_state edges_pre ~f:(fun call_state (access, (addr_pre_dest, _)) -> ~init:call_state edges_pre ~f:(fun call_state (access, (addr_pre_dest, _)) ->
@ -572,8 +623,8 @@ module PrePost = struct
; in_call= invalidation }) ; in_call= invalidation })
| AddressOfCppTemporary (_, _) | AddressOfCppTemporary (_, _)
| AddressOfStackVariable (_, _, _) | AddressOfStackVariable (_, _, _)
| Arithmetic _
| Closure _ | Closure _
| Constant _
| MustBeValid _ | MustBeValid _
| StdVectorReserve | StdVectorReserve
| WrittenTo _ -> | WrittenTo _ ->
@ -839,9 +890,10 @@ module PrePost = struct
match match
materialize_pre callee_proc_name call_location pre_post ~formals ~actuals empty_call_state materialize_pre callee_proc_name call_location pre_post ~formals ~actuals empty_call_state
with with
| exception Aliasing -> | exception CannotApplyPre reason ->
(* can't make sense of the pre-condition in the current context: give up on that particular (* can't make sense of the pre-condition in the current context: give up on that particular
pre/post pair *) pre/post pair *)
L.d_printfln "Cannot apply precondition: %a" pp_cannot_apply_pre reason ;
Ok None Ok None
| None -> | None ->
(* couldn't apply the pre for some technical reason (as in: not by the fault of the (* couldn't apply the pre for some technical reason (as in: not by the fault of the

@ -45,7 +45,11 @@ module Memory : sig
module Access = BaseMemory.Access module Access = BaseMemory.Access
module Edges = BaseMemory.Edges module Edges = BaseMemory.Edges
val abduce_attribute : AbstractValue.t -> Attribute.t -> t -> t
(** add the attribute to the pre, if meaningful (does not modify the post) *)
val add_attribute : AbstractValue.t -> Attribute.t -> t -> t val add_attribute : AbstractValue.t -> Attribute.t -> t -> t
(** add the attribute only to the post *)
val add_edge : val add_edge :
AbstractValue.t * ValueHistory.t AbstractValue.t * ValueHistory.t
@ -76,7 +80,7 @@ module Memory : sig
(** [eval_edge (addr,hist) access astate] follows the edge [addr --access--> .] in memory and (** [eval_edge (addr,hist) access astate] follows the edge [addr --access--> .] in memory and
returns what it points to or creates a fresh value if that edge didn't exist. *) returns what it points to or creates a fresh value if that edge didn't exist. *)
val get_constant : AbstractValue.t -> t -> Const.t option val get_arithmetic : AbstractValue.t -> t -> Arithmetic.t option
end end
val is_local : Var.t -> t -> bool val is_local : Var.t -> t -> bool

@ -0,0 +1,68 @@
(*
* 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
module F = Format
type t = EqualTo of Const.t [@@deriving compare]
let pp fmt = function EqualTo c -> F.fprintf fmt "=%a" (Const.pp Pp.text) c
(** booleans with \top *)
module TBool = struct
type t = True | False | Top
end
let flip_abduced (tbool, c1, c2) = (tbool, c2, c1)
let rec abduce_eq a1 a2 =
match (a1, a2) with
| Some (EqualTo c1), Some (EqualTo c2) when Const.equal c1 c2 ->
(TBool.True, None, None)
| Some (EqualTo _c1), Some (EqualTo _c2) (* c1≠c2 *) ->
(TBool.False, None, None)
| None, Some _ ->
abduce_eq a2 a1 |> flip_abduced
| Some (EqualTo _c), None ->
(TBool.True, None, a1)
| None, None ->
(TBool.Top, None, None)
let abduce_ne a1 a2 =
match (a1, a2) with
| Some (EqualTo c1), Some (EqualTo c2) when Const.equal c1 c2 ->
(TBool.False, None, None)
| Some (EqualTo _c1), Some (EqualTo _c2) (* c1≠c2 *) ->
(TBool.True, None, None)
| None, Some _ | Some _, None ->
(* cannot express ≠c so go to Top *)
(TBool.Top, None, None)
| None, None ->
(TBool.Top, None, None)
let abduce_binop_constraints ~negated (bop : Binop.t) a1 a2 =
let open Binop in
match (bop, negated) with
| Eq, false | Ne, true ->
abduce_eq a1 a2
| Eq, true | Ne, false ->
abduce_ne a1 a2
| _ ->
(TBool.Top, None, None)
let abduce_binop_is_true_aux ~negated bop a1_opt a2_opt =
Logging.d_printfln "abduce_binop_is_true ~negated:%b %s (%a) (%a)" negated
(Binop.str Pp.text bop) (Pp.option pp) a1_opt (Pp.option pp) a2_opt ;
abduce_binop_constraints ~negated bop a1_opt a2_opt
let abduce_binop_is_true ~negated bop v1 v2 =
let result, abduced1, abduced2 = abduce_binop_is_true_aux ~negated bop v1 v2 in
let can_go_through = match result with Top | True -> true | False -> false in
(can_go_through, abduced1, abduced2)

@ -0,0 +1,25 @@
(*
* 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
module F = Format
type t = EqualTo of Const.t [@@deriving compare]
val pp : F.formatter -> t -> unit
val abduce_binop_is_true :
negated:bool -> Binop.t -> t option -> t option -> bool * t option * t option
(** given [arith_lhs_opt bop arith_rhs_opt], return a triple
[(satisfiable,abduced_lhs_opt,abduced_rhs_opt)] such that (taking lhs=true if lhs_opt is [None],
same for rhs):
- [satisfiable] iff lhs bop rhs
- [abduced_lhs_opt=Some alhs] if [satisfiable] and (lhs bop rhs => alhslhs) (and similarly for rhs)
- likewise if [negated] with (lhs bop rhs = ) in the two points above
*)

@ -6,6 +6,7 @@
*) *)
open! IStd open! IStd
module F = Format module F = Format
module Arithmetic = PulseArithmetic
module Invalidation = PulseInvalidation module Invalidation = PulseInvalidation
module Trace = PulseTrace module Trace = PulseTrace
module ValueHistory = PulseValueHistory module ValueHistory = PulseValueHistory
@ -28,8 +29,8 @@ module Attribute = struct
type t = type t =
| AddressOfCppTemporary of Var.t * ValueHistory.t | AddressOfCppTemporary of Var.t * ValueHistory.t
| AddressOfStackVariable of Var.t * Location.t * ValueHistory.t | AddressOfStackVariable of Var.t * Location.t * ValueHistory.t
| Arithmetic of Arithmetic.t
| Closure of Typ.Procname.t | Closure of Typ.Procname.t
| Constant of Const.t
| Invalid of Invalidation.t Trace.t | Invalid of Invalidation.t Trace.t
| MustBeValid of unit Trace.t | MustBeValid of unit Trace.t
| StdVectorReserve | StdVectorReserve
@ -59,7 +60,7 @@ module Attribute = struct
let std_vector_reserve_rank = Variants.to_rank StdVectorReserve let std_vector_reserve_rank = Variants.to_rank StdVectorReserve
let const_rank = Variants.to_rank (Constant (Const.Cint IntLit.zero)) let const_rank = Variants.to_rank (Arithmetic (Arithmetic.EqualTo (Cint IntLit.zero)))
let pp f attribute = let pp f attribute =
let pp_string_if_debug string fmt () = let pp_string_if_debug string fmt () =
@ -72,8 +73,8 @@ module Attribute = struct
F.fprintf f "s&%a (%a) at %a" Var.pp var ValueHistory.pp history Location.pp location F.fprintf f "s&%a (%a) at %a" Var.pp var ValueHistory.pp history Location.pp location
| Closure pname -> | Closure pname ->
Typ.Procname.pp f pname Typ.Procname.pp f pname
| Constant c -> | Arithmetic phi ->
F.fprintf f "=%a" (Const.pp Pp.text) c Arithmetic.pp f phi
| Invalid invalidation -> | Invalid invalidation ->
F.fprintf f "Invalid %a" (Trace.pp Invalidation.pp) invalidation F.fprintf f "Invalid %a" (Trace.pp Invalidation.pp) invalidation
| MustBeValid action -> | MustBeValid action ->
@ -131,11 +132,11 @@ module Attributes = struct
|| Option.is_some (Set.find_rank attrs Attribute.invalid_rank) || Option.is_some (Set.find_rank attrs Attribute.invalid_rank)
let get_constant attrs = let get_arithmetic attrs =
Set.find_rank attrs Attribute.const_rank Set.find_rank attrs Attribute.const_rank
|> Option.map ~f:(fun attr -> |> Option.map ~f:(fun attr ->
let[@warning "-8"] (Attribute.Constant c) = attr in let[@warning "-8"] (Attribute.Arithmetic a) = attr in
c ) a )
include Set include Set

@ -6,6 +6,7 @@
*) *)
open! IStd open! IStd
module F = Format module F = Format
module Arithmetic = PulseArithmetic
module Invalidation = PulseInvalidation module Invalidation = PulseInvalidation
module Trace = PulseTrace module Trace = PulseTrace
module ValueHistory = PulseValueHistory module ValueHistory = PulseValueHistory
@ -13,8 +14,8 @@ module ValueHistory = PulseValueHistory
type t = type t =
| AddressOfCppTemporary of Var.t * ValueHistory.t | AddressOfCppTemporary of Var.t * ValueHistory.t
| AddressOfStackVariable of Var.t * Location.t * ValueHistory.t | AddressOfStackVariable of Var.t * Location.t * ValueHistory.t
| Arithmetic of Arithmetic.t
| Closure of Typ.Procname.t | Closure of Typ.Procname.t
| Constant of Const.t
| Invalid of Invalidation.t Trace.t | Invalid of Invalidation.t Trace.t
| MustBeValid of unit Trace.t | MustBeValid of unit Trace.t
| StdVectorReserve | StdVectorReserve
@ -30,7 +31,7 @@ module Attributes : sig
val get_closure_proc_name : t -> Typ.Procname.t option val get_closure_proc_name : t -> Typ.Procname.t option
val get_constant : t -> Const.t option val get_arithmetic : t -> Arithmetic.t option
val get_invalid : t -> Invalidation.t Trace.t option val get_invalid : t -> Invalidation.t Trace.t option

@ -89,7 +89,7 @@ let get_attribute getter address memory =
let get_closure_proc_name = get_attribute Attributes.get_closure_proc_name let get_closure_proc_name = get_attribute Attributes.get_closure_proc_name
let get_constant = get_attribute Attributes.get_constant let get_arithmetic = get_attribute Attributes.get_arithmetic
let get_must_be_valid = get_attribute Attributes.get_must_be_valid let get_must_be_valid = get_attribute Attributes.get_must_be_valid

@ -60,7 +60,7 @@ val check_valid : AbstractValue.t -> t -> (unit, Invalidation.t Trace.t) result
val get_closure_proc_name : AbstractValue.t -> t -> Typ.Procname.t option val get_closure_proc_name : AbstractValue.t -> t -> Typ.Procname.t option
val get_constant : AbstractValue.t -> t -> Const.t option val get_arithmetic : AbstractValue.t -> t -> Arithmetic.t option
val get_must_be_valid : AbstractValue.t -> t -> unit Trace.t option val get_must_be_valid : AbstractValue.t -> t -> unit Trace.t option

@ -9,6 +9,7 @@ open! IStd
(** Basic Pulse modules that are safe to use in any module *) (** Basic Pulse modules that are safe to use in any module *)
module AbstractValue = PulseAbstractValue module AbstractValue = PulseAbstractValue
module Arithmetic = PulseArithmetic
module Attribute = PulseAttribute module Attribute = PulseAttribute
module Attributes = PulseAttribute.Attributes module Attributes = PulseAttribute.Attributes
module CallEvent = PulseCallEvent module CallEvent = PulseCallEvent

@ -134,7 +134,7 @@ let eval location exp0 astate =
| Const c -> | Const c ->
(* TODO: make identical const the same address *) (* TODO: make identical const the same address *)
let addr = AbstractValue.mk_fresh () in let addr = AbstractValue.mk_fresh () in
let astate = Memory.add_attribute addr (Constant c) astate in let astate = Memory.add_attribute addr (Arithmetic (Arithmetic.EqualTo c)) astate in
Ok (astate, (addr, [])) Ok (astate, (addr, []))
| Sizeof _ | UnOp _ | BinOp _ | Exn _ -> | Sizeof _ | UnOp _ | BinOp _ | Exn _ ->
Ok (astate, (AbstractValue.mk_fresh (), (* TODO history *) [])) Ok (astate, (AbstractValue.mk_fresh (), (* TODO history *) []))
@ -142,57 +142,39 @@ let eval location exp0 astate =
eval exp0 astate eval exp0 astate
type eval_result = EvalConst of Const.t | EvalAddr of AbstractValue.t let eval_arith location exp astate =
let eval_to_const location exp astate =
match (exp : Exp.t) with match (exp : Exp.t) with
| Const c -> | Const c ->
Ok (astate, EvalConst c) Ok (astate, None, Some (Arithmetic.EqualTo c))
| exp -> ( | exp -> (
eval location exp astate eval location exp astate
>>| fun (astate, (addr, _)) -> >>| fun (astate, (addr, _)) ->
match Memory.get_constant addr astate with match Memory.get_arithmetic addr astate with
| Some c -> | Some a ->
(astate, EvalConst c) (astate, Some addr, Some a)
| None -> | None ->
(astate, EvalAddr addr) ) (astate, Some addr, None) )
let eval_binop ~negated (bop : Binop.t) c1 c2 =
match (bop, negated) with
| Eq, false | Ne, true ->
Const.equal c1 c2
| Eq, true | Ne, false ->
not (Const.equal c1 c2)
| _ ->
true
module TBool = struct let record_abduced addr_opt arith_opt astate =
(** booleans with \top *) match Option.both addr_opt arith_opt with
type t = True | False | Top | None ->
astate
| Some (addr, arith) ->
let attribute = Attribute.Arithmetic arith in
Memory.abduce_attribute addr attribute astate |> Memory.add_attribute addr attribute
let of_bool b = if b then True else False
end
let rec eval_cond ~negated location exp astate = let rec eval_cond ~negated location exp astate =
match (exp : Exp.t) with match (exp : Exp.t) with
| BinOp (bop, e1, e2) -> ( | BinOp (bop, e1, e2) ->
eval_to_const location e1 astate eval_arith location e1 astate
>>= fun (astate, eval1) -> >>= fun (astate, addr1, eval1) ->
eval_to_const location e2 astate eval_arith location e2 astate
>>| fun (astate, eval2) -> >>| fun (astate, addr2, eval2) ->
match (eval1, eval2) with let result, abduced1, abduced2 = Arithmetic.abduce_binop_is_true ~negated bop eval1 eval2 in
| EvalConst c1, EvalConst c2 -> let astate = record_abduced addr1 abduced1 astate |> record_abduced addr2 abduced2 in
(astate, eval_binop ~negated bop c1 c2 |> TBool.of_bool) (astate, result)
| EvalAddr _, EvalAddr _ ->
(astate, TBool.Top)
| EvalAddr v, EvalConst c | EvalConst c, EvalAddr v -> (
match (bop, negated) with
| Eq, false | Ne, true ->
(Memory.add_attribute v (Constant c) astate, TBool.True)
| _ ->
(astate, TBool.Top) ) )
| UnOp (LNot, exp', _) -> | UnOp (LNot, exp', _) ->
eval_cond ~negated:(not negated) location exp' astate eval_cond ~negated:(not negated) location exp' astate
| exp -> | exp ->
@ -200,12 +182,7 @@ let rec eval_cond ~negated location exp astate =
eval_cond ~negated location (Exp.BinOp (Ne, exp, zero)) astate eval_cond ~negated location (Exp.BinOp (Ne, exp, zero)) astate
let assert_is_true location ~condition astate = let assert_is_true location ~condition astate = eval_cond ~negated:false location condition astate
eval_cond ~negated:false location condition astate
>>| fun (astate, result) ->
let can_go_through = match (result : TBool.t) with Top | True -> true | False -> false in
(astate, can_go_through)
let eval_deref location exp astate = let eval_deref location exp astate =
eval location exp astate eval location exp astate

@ -11,7 +11,7 @@ codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `a` of deduplication::SomeTemplatedClass<int>::lifetime_error_bad,when calling `deduplication::SomeTemplatedClass<int>::templated_wrapper_delete_ok` here,parameter `a` of deduplication::SomeTemplatedClass<int>::templated_wrapper_delete_ok,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `a` of deduplication::SomeTemplatedClass<int>::lifetime_error_bad,when calling `deduplication::SomeTemplatedClass<int>::templated_wrapper_access_ok` here,parameter `a` of deduplication::SomeTemplatedClass<int>::templated_wrapper_access_ok,invalid access occurs here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::SomeTemplatedClass<int>::lifetime_error_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `a` of deduplication::SomeTemplatedClass<int>::lifetime_error_bad,when calling `deduplication::SomeTemplatedClass<int>::templated_wrapper_delete_ok` here,parameter `a` of deduplication::SomeTemplatedClass<int>::templated_wrapper_delete_ok,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `a` of deduplication::SomeTemplatedClass<int>::lifetime_error_bad,when calling `deduplication::SomeTemplatedClass<int>::templated_wrapper_access_ok` here,parameter `a` of deduplication::SomeTemplatedClass<int>::templated_wrapper_access_ok,invalid access occurs here]
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<_Bool>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,when calling `deduplication::templated_delete_function<_Bool>` here,parameter `a` of deduplication::templated_delete_function<_Bool>,was invalidated by `delete`,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function<_Bool>` here,parameter `a` of deduplication::templated_access_function<_Bool>,invalid access occurs here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<_Bool>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,when calling `deduplication::templated_delete_function<_Bool>` here,parameter `a` of deduplication::templated_delete_function<_Bool>,was invalidated by `delete`,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function<_Bool>` here,parameter `a` of deduplication::templated_access_function<_Bool>,invalid access occurs here]
codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<int>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,when calling `deduplication::templated_delete_function<int>` here,parameter `a` of deduplication::templated_delete_function<int>,was invalidated by `delete`,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function<int>` here,parameter `a` of deduplication::templated_access_function<int>,invalid access occurs here] codetoanalyze/cpp/pulse/deduplication.cpp, deduplication::templated_function_bad<int>, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,assigned,when calling `deduplication::templated_delete_function<int>` here,parameter `a` of deduplication::templated_delete_function<int>,was invalidated by `delete`,use-after-lifetime part of the trace starts here,assigned,when calling `deduplication::templated_access_function<int>` here,parameter `a` of deduplication::templated_access_function<int>,invalid access occurs here]
codetoanalyze/cpp/pulse/fbstring.cpp, FP_pass_to_copy_ok, 6, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `s` declared here,when calling `copy_fbstring` here,parameter `s` of copy_fbstring,passed as argument to `LikeFBString::LikeFBString`,parameter `src` of LikeFBString::LikeFBString,passed as argument to `LikeFBString::copyLarge`,parameter `src` of LikeFBString::copyLarge,assigned,return from call to `LikeFBString::copyLarge`,return from call to `LikeFBString::LikeFBString`,when calling `LikeFBString::~LikeFBString` here,parameter `this` of LikeFBString::~LikeFBString,when calling `LikeFBString::__infer_inner_destructor_~LikeFBString` here,parameter `this` of LikeFBString::__infer_inner_destructor_~LikeFBString,when calling `LikeFBString::decr_ref_count` here,parameter `this` of LikeFBString::decr_ref_count,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,variable `s` declared here,when calling `LikeFBString::~LikeFBString` here,parameter `this` of LikeFBString::~LikeFBString,when calling `LikeFBString::__infer_inner_destructor_~LikeFBString` here,parameter `this` of LikeFBString::__infer_inner_destructor_~LikeFBString,invalid access occurs here] codetoanalyze/cpp/pulse/fbstring.cpp, FP_pass_to_copy_ok, 6, USE_AFTER_FREE, no_bucket, ERROR, [invalidation part of the trace starts here,variable `s` declared here,when calling `copy_fbstring` here,parameter `s` of copy_fbstring,passed as argument to `LikeFBString::LikeFBString`,parameter `src` of LikeFBString::LikeFBString,passed as argument to `LikeFBString::copyLarge`,parameter `src` of LikeFBString::copyLarge,assigned,return from call to `LikeFBString::copyLarge`,return from call to `LikeFBString::LikeFBString`,when calling `LikeFBString::~LikeFBString` here,parameter `this` of LikeFBString::~LikeFBString,when calling `LikeFBString::__infer_inner_destructor_~LikeFBString` here,parameter `this` of LikeFBString::__infer_inner_destructor_~LikeFBString,when calling `LikeFBString::decr_ref_count` here,parameter `this` of LikeFBString::decr_ref_count,was invalidated by call to `free()`,use-after-lifetime part of the trace starts here,variable `s` declared here,when calling `LikeFBString::~LikeFBString` here,parameter `this` of LikeFBString::~LikeFBString,when calling `LikeFBString::__infer_inner_destructor_~LikeFBString` here,parameter `this` of LikeFBString::__infer_inner_destructor_~LikeFBString,when calling `LikeFBString::decr_ref_count` here,parameter `this` of LikeFBString::decr_ref_count,invalid access occurs here]
codetoanalyze/cpp/pulse/folly_DestructorGuard.cpp, UsingDelayedDestruction::double_delete_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `this` of UsingDelayedDestruction::double_delete_bad,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `this` of UsingDelayedDestruction::double_delete_bad,invalid access occurs here] codetoanalyze/cpp/pulse/folly_DestructorGuard.cpp, UsingDelayedDestruction::double_delete_bad, 2, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `this` of UsingDelayedDestruction::double_delete_bad,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `this` of UsingDelayedDestruction::double_delete_bad,invalid access occurs here]
codetoanalyze/cpp/pulse/frontend.cpp, deref_null_namespace_alias_ptr_bad, 4, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `some::thing::bad_ptr` here,assigned,was invalidated by `delete`,use-after-lifetime part of the trace starts here,passed as argument to `some::thing::bad_ptr`,return from call to `some::thing::bad_ptr`,assigned,invalid access occurs here] codetoanalyze/cpp/pulse/frontend.cpp, deref_null_namespace_alias_ptr_bad, 4, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,when calling `some::thing::bad_ptr` here,assigned,was invalidated by `delete`,use-after-lifetime part of the trace starts here,passed as argument to `some::thing::bad_ptr`,return from call to `some::thing::bad_ptr`,assigned,invalid access occurs here]
codetoanalyze/cpp/pulse/interprocedural.cpp, access_to_invalidated_alias2_bad, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of access_to_invalidated_alias2_bad,assigned,when calling `invalidate_and_set_to_null` here,parameter `x_ptr` of invalidate_and_set_to_null,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `x` of access_to_invalidated_alias2_bad,when calling `wraps_read` here,parameter `x` of wraps_read,when calling `wraps_read_inner` here,parameter `x` of wraps_read_inner,invalid access occurs here] codetoanalyze/cpp/pulse/interprocedural.cpp, access_to_invalidated_alias2_bad, 3, USE_AFTER_DELETE, no_bucket, ERROR, [invalidation part of the trace starts here,parameter `x` of access_to_invalidated_alias2_bad,assigned,when calling `invalidate_and_set_to_null` here,parameter `x_ptr` of invalidate_and_set_to_null,was invalidated by `delete`,use-after-lifetime part of the trace starts here,parameter `x` of access_to_invalidated_alias2_bad,when calling `wraps_read` here,parameter `x` of wraps_read,when calling `wraps_read_inner` here,parameter `x` of wraps_read_inner,invalid access occurs here]

Loading…
Cancel
Save