[pulse] rename `Location` -> `Address` and better reporting

Summary:
`Location` was clashing with the `Location` module, so use `Address`
instead.

When invalidating an address, remember the "actor" of its invalidation,
i.e. the access expression leading to the address and the source
location of the corresponding instruction.

When checking accesses, also pass the actor responsible for the access,
so that when we raise an error we know:
1. when and why a location was invalidated
2. when and why we tried to read it after that

Reviewed By: mbouaziz

Differential Revision: D10446282

fbshipit-source-id: 3ca4fb3d4
master
Jules Villard 6 years ago committed by Facebook Github Bot
parent dd220a0fb4
commit 47867a8fdc

@ -8,13 +8,17 @@ open! IStd
module F = Format module F = Format
open Result.Monad_infix open Result.Monad_infix
let check_error summary loc = function let report summary diagnostic =
let open PulseDomain.Diagnostic in
Reporting.log_error summary ~loc:(get_location diagnostic) ~ltr:(get_trace diagnostic)
(get_issue_type diagnostic) (get_message diagnostic)
let check_error summary = function
| Ok astate -> | Ok astate ->
astate astate
| Error (astate, diagnostic) -> | Error (astate, diagnostic) ->
let message = PulseDomain.Diagnostic.to_string diagnostic in report summary diagnostic ; astate
Reporting.log_error summary ~loc IssueType.use_after_lifetime message ;
astate
module TransferFunctions (CFG : ProcCfg.S) = struct module TransferFunctions (CFG : ProcCfg.S) = struct
@ -23,7 +27,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
type extras = Summary.t type extras = Summary.t
let dispatch_call ret (call : HilInstr.call) (actuals : HilExp.t list) _flags _call_loc astate = let dispatch_call ret (call : HilInstr.call) (actuals : HilExp.t list) _flags call_loc astate =
let model = let model =
match call with match call with
| Indirect _ -> | Indirect _ ->
@ -32,31 +36,31 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Direct callee_pname -> | Direct callee_pname ->
PulseModels.dispatch callee_pname PulseModels.dispatch callee_pname
in in
match model with None -> Ok astate | Some model -> model ~ret ~actuals astate match model with None -> Ok astate | Some model -> model call_loc ~ret ~actuals astate
let exec_instr (astate : PulseDomain.t) {ProcData.extras= summary} _cfg_node (instr : HilInstr.t) let exec_instr (astate : PulseDomain.t) {ProcData.extras= summary} _cfg_node (instr : HilInstr.t)
= =
match instr with match instr with
| Assign (lhs_access, rhs_exp, loc) -> | Assign (lhs_access, rhs_exp, loc) ->
(* try to evaluate [rhs_exp] down to an abstract location or generate a fresh one *) (* try to evaluate [rhs_exp] down to an abstract address or generate a fresh one *)
let rhs_result = let rhs_result =
match rhs_exp with match rhs_exp with
| AccessExpression rhs_access -> | AccessExpression rhs_access ->
PulseDomain.read rhs_access astate PulseDomain.read loc rhs_access astate
| _ -> | _ ->
PulseDomain.read_all (HilExp.get_access_exprs rhs_exp) astate PulseDomain.read_all loc (HilExp.get_access_exprs rhs_exp) astate
>>= fun astate -> Ok (astate, PulseDomain.AbstractLocation.mk_fresh ()) >>= fun astate -> Ok (astate, PulseDomain.AbstractAddress.mk_fresh ())
in in
Result.bind rhs_result ~f:(fun (astate, rhs_value) -> Result.bind rhs_result ~f:(fun (astate, rhs_value) ->
PulseDomain.write lhs_access rhs_value astate ) PulseDomain.write loc lhs_access rhs_value astate )
|> check_error summary loc |> check_error summary
| Assume (condition, _, _, loc) -> | Assume (condition, _, _, loc) ->
PulseDomain.read_all (HilExp.get_access_exprs condition) astate |> check_error summary loc PulseDomain.read_all loc (HilExp.get_access_exprs condition) astate |> check_error summary
| Call (ret, call, actuals, flags, loc) -> | Call (ret, call, actuals, flags, loc) ->
PulseDomain.read_all (List.concat_map actuals ~f:HilExp.get_access_exprs) astate PulseDomain.read_all loc (List.concat_map actuals ~f:HilExp.get_access_exprs) astate
>>= dispatch_call ret call actuals flags loc >>= dispatch_call ret call actuals flags loc
|> check_error summary loc |> check_error summary
let pp_session_name _node fmt = F.pp_print_string fmt "Pulse" let pp_session_name _node fmt = F.pp_print_string fmt "Pulse"

@ -10,7 +10,7 @@ module L = Logging
open Result.Monad_infix open Result.Monad_infix
(** An abstract address in memory. *) (** An abstract address in memory. *)
module AbstractLocation : sig module AbstractAddress : sig
type t = private int [@@deriving compare] type t = private int [@@deriving compare]
val equal : t -> t -> bool val equal : t -> t -> bool
@ -33,18 +33,18 @@ end = struct
let pp = F.pp_print_int let pp = F.pp_print_int
end end
module AbstractLocationDomain : AbstractDomain.S with type astate = AbstractLocation.t = struct module AbstractAddressDomain : AbstractDomain.S with type astate = AbstractAddress.t = struct
type astate = AbstractLocation.t type astate = AbstractAddress.t
let ( <= ) ~lhs ~rhs = AbstractLocation.equal lhs rhs let ( <= ) ~lhs ~rhs = AbstractAddress.equal lhs rhs
let join l1 l2 = let join l1 l2 =
if AbstractLocation.equal l1 l2 then l1 else (* TODO: scary *) AbstractLocation.mk_fresh () if AbstractAddress.equal l1 l2 then l1 else (* TODO: scary *) AbstractAddress.mk_fresh ()
let widen ~prev ~next ~num_iters:_ = join prev next let widen ~prev ~next ~num_iters:_ = join prev next
let pp = AbstractLocation.pp let pp = AbstractAddress.pp
end end
module Access = struct module Access = struct
@ -53,32 +53,64 @@ module Access = struct
let pp = AccessPath.pp_access let pp = AccessPath.pp_access
end end
module MemoryEdges = AbstractDomain.InvertedMap (Access) (AbstractLocationDomain) module MemoryEdges = AbstractDomain.InvertedMap (Access) (AbstractAddressDomain)
module MemoryDomain = struct module MemoryDomain = struct
include AbstractDomain.InvertedMap (AbstractLocation) (MemoryEdges) include AbstractDomain.InvertedMap (AbstractAddress) (MemoryEdges)
let add_edge loc_src access loc_end memory = let add_edge addr_src access addr_end memory =
let edges = let edges =
match find_opt loc_src memory with Some edges -> edges | None -> MemoryEdges.empty match find_opt addr_src memory with Some edges -> edges | None -> MemoryEdges.empty
in in
add loc_src (MemoryEdges.add access loc_end edges) memory add addr_src (MemoryEdges.add access addr_end edges) memory
let find_edge_opt loc access memory = let find_edge_opt addr access memory =
let open Option.Monad_infix in let open Option.Monad_infix in
find_opt loc memory >>= MemoryEdges.find_opt access find_opt addr memory >>= MemoryEdges.find_opt access
end end
module AliasingDomain = AbstractDomain.InvertedMap (Var) (AbstractLocationDomain) module AliasingDomain = AbstractDomain.InvertedMap (Var) (AbstractAddressDomain)
module AbstractLocationsDomain = AbstractDomain.FiniteSet (AbstractLocation)
module InvalidLocationsDomain = AbstractLocationsDomain type actor = {access_expr: AccessExpression.t; location: Location.t}
let pp_actor f {access_expr; location} =
F.fprintf f "%a@%a" AccessExpression.pp access_expr Location.pp location
module type InvalidAddressesDomain = sig
include AbstractDomain.S
val empty : astate
val add : AbstractAddress.t -> actor -> astate -> astate
val get_invalidation : AbstractAddress.t -> astate -> actor option
end
module InvalidAddressesDomain : InvalidAddressesDomain = struct
module InvalidationReason = struct
type astate = actor
let join actor _ = actor
let ( <= ) ~lhs:_ ~rhs:_ = true
let widen ~prev ~next:_ ~num_iters:_ = prev
let pp = pp_actor
end
include AbstractDomain.Map (AbstractAddress) (InvalidationReason)
let get_invalidation address invalids = find_opt address invalids
end
type t = type t =
{heap: MemoryDomain.astate; stack: AliasingDomain.astate; invalids: InvalidLocationsDomain.astate} {heap: MemoryDomain.astate; stack: AliasingDomain.astate; invalids: InvalidAddressesDomain.astate}
let initial = let initial =
{heap= MemoryDomain.empty; stack= AliasingDomain.empty; invalids= AbstractLocationsDomain.empty} {heap= MemoryDomain.empty; stack= AliasingDomain.empty; invalids= InvalidAddressesDomain.empty}
module Domain : AbstractDomain.S with type astate = t = struct module Domain : AbstractDomain.S with type astate = t = struct
@ -91,7 +123,7 @@ module Domain : AbstractDomain.S with type astate = t = struct
into the heap. *) into the heap. *)
let ( <= ) ~lhs ~rhs = let ( <= ) ~lhs ~rhs =
phys_equal lhs rhs phys_equal lhs rhs
|| InvalidLocationsDomain.( <= ) ~lhs:lhs.invalids ~rhs:rhs.invalids || InvalidAddressesDomain.( <= ) ~lhs:lhs.invalids ~rhs:rhs.invalids
&& AliasingDomain.( <= ) ~lhs:lhs.stack ~rhs:rhs.stack && AliasingDomain.( <= ) ~lhs:lhs.stack ~rhs:rhs.stack
&& MemoryDomain.( <= ) ~lhs:lhs.heap ~rhs:rhs.heap && MemoryDomain.( <= ) ~lhs:lhs.heap ~rhs:rhs.heap
@ -102,7 +134,7 @@ module Domain : AbstractDomain.S with type astate = t = struct
else else
{ heap= MemoryDomain.join astate1.heap astate2.heap { heap= MemoryDomain.join astate1.heap astate2.heap
; stack= AliasingDomain.join astate1.stack astate2.stack ; stack= AliasingDomain.join astate1.stack astate2.stack
; invalids= InvalidLocationsDomain.join astate1.invalids astate2.invalids } ; invalids= InvalidAddressesDomain.join astate1.invalids astate2.invalids }
let max_widening = 5 let max_widening = 5
@ -116,117 +148,146 @@ module Domain : AbstractDomain.S with type astate = t = struct
else else
{ heap= MemoryDomain.widen ~num_iters ~prev:prev.heap ~next:next.heap { heap= MemoryDomain.widen ~num_iters ~prev:prev.heap ~next:next.heap
; stack= AliasingDomain.widen ~num_iters ~prev:prev.stack ~next:next.stack ; stack= AliasingDomain.widen ~num_iters ~prev:prev.stack ~next:next.stack
; invalids= InvalidLocationsDomain.widen ~num_iters ~prev:prev.invalids ~next:next.invalids ; invalids= InvalidAddressesDomain.widen ~num_iters ~prev:prev.invalids ~next:next.invalids
} }
let pp fmt {heap; stack; invalids} = let pp fmt {heap; stack; invalids} =
F.fprintf fmt "{@[<v1> heap=@[<hv>%a@];@;stack=@[<hv>%a@];@;invalids=@[<hv>%a@];@]}" F.fprintf fmt "{@[<v1> heap=@[<hv>%a@];@;stack=@[<hv>%a@];@;invalids=@[<hv>%a@];@]}"
MemoryDomain.pp heap AliasingDomain.pp stack InvalidLocationsDomain.pp invalids MemoryDomain.pp heap AliasingDomain.pp stack InvalidAddressesDomain.pp invalids
end end
include Domain include Domain
module Diagnostic = struct module Diagnostic = struct
(* TODO: more structured error type so that we can actually report something informative about type t =
the variables being accessed along with a trace *) | AccessToInvalidAddress of
type t = InvalidLocation of AbstractLocation.t { invalidated_at: actor
; accessed_by: actor
; address: AbstractAddress.t }
let get_location (AccessToInvalidAddress {accessed_by= {location}}) = location
let to_string (InvalidLocation loc) = F.asprintf "invalid location %a" AbstractLocation.pp loc let get_message (AccessToInvalidAddress {accessed_by; invalidated_at; address}) =
let pp_debug_address f =
if Config.debug_mode then F.fprintf f " (debug: %a)" AbstractAddress.pp address
in
F.asprintf "`%a` accesses address `%a` past its lifetime%t" AccessExpression.pp
accessed_by.access_expr AccessExpression.pp invalidated_at.access_expr pp_debug_address
let get_trace (AccessToInvalidAddress {accessed_by; invalidated_at}) =
[ Errlog.make_trace_element 0 invalidated_at.location
(F.asprintf "invalidated `%a` here" AccessExpression.pp invalidated_at.access_expr)
[]
; Errlog.make_trace_element 0 accessed_by.location
(F.asprintf "accessed `%a` here" AccessExpression.pp accessed_by.access_expr)
[] ]
let get_issue_type (AccessToInvalidAddress _) = IssueType.use_after_lifetime
end end
type 'a access_result = ('a, t * Diagnostic.t) result type 'a access_result = ('a, t * Diagnostic.t) result
(** Check that the location is not known to be invalid *) (** Check that the address is not known to be invalid *)
let check_loc_access loc astate = let check_addr_access actor address astate =
if AbstractLocationsDomain.mem loc astate.invalids then match InvalidAddressesDomain.get_invalidation address astate.invalids with
Error (astate, Diagnostic.InvalidLocation loc) | Some invalidated_at ->
else Ok astate Error
(astate, Diagnostic.AccessToInvalidAddress {invalidated_at; accessed_by= actor; address})
| None ->
Ok astate
(** Walk the heap starting from [loc] and following [path]. Stop either at the element before last (** Walk the heap starting from [addr] and following [path]. Stop either at the element before last
and return [new_loc] if [overwrite_last] is [Some new_loc], or go until the end of the path if it and return [new_addr] if [overwrite_last] is [Some new_addr], or go until the end of the path if it
is [None]. Create more locations into the heap as needed to follow the [path]. Check that each is [None]. Create more addresses into the heap as needed to follow the [path]. Check that each
location reached is valid. *) address reached is valid. *)
let rec walk ~overwrite_last loc path astate = let rec walk actor ~overwrite_last addr path astate =
match (path, overwrite_last) with match (path, overwrite_last) with
| [], None -> | [], None ->
Ok (astate, loc) Ok (astate, addr)
| [], Some _ -> | [], Some _ ->
L.die InternalError "Cannot overwrite last location in empty path" L.die InternalError "Cannot overwrite last address in empty path"
| [a], Some new_loc -> | [a], Some new_addr ->
check_loc_access loc astate check_addr_access actor addr astate
>>| fun astate -> >>| fun astate ->
let heap = MemoryDomain.add_edge loc a new_loc astate.heap in let heap = MemoryDomain.add_edge addr a new_addr astate.heap in
({astate with heap}, new_loc) ({astate with heap}, new_addr)
| a :: path, _ -> ( | a :: path, _ -> (
check_loc_access loc astate check_addr_access actor addr astate
>>= fun astate -> >>= fun astate ->
match MemoryDomain.find_edge_opt loc a astate.heap with match MemoryDomain.find_edge_opt addr a astate.heap with
| None -> | None ->
let loc' = AbstractLocation.mk_fresh () in let addr' = AbstractAddress.mk_fresh () in
let heap = MemoryDomain.add_edge loc a loc' astate.heap in let heap = MemoryDomain.add_edge addr a addr' astate.heap in
let astate = {astate with heap} in let astate = {astate with heap} in
walk ~overwrite_last loc' path astate walk actor ~overwrite_last addr' path astate
| Some loc' -> | Some addr' ->
walk ~overwrite_last loc' path astate ) walk actor ~overwrite_last addr' path astate )
(** add locations to the state to give a location to the destination of the given access path *) (** add addresses to the state to give a address to the destination of the given access path *)
let walk_access_expr ?overwrite_last astate access_expr = let walk_access_expr ?overwrite_last astate access_expr location =
let (access_var, _), access_list = AccessExpression.to_access_path access_expr in let (access_var, _), access_list = AccessExpression.to_access_path access_expr in
match (overwrite_last, access_list) with match (overwrite_last, access_list) with
| Some new_loc, [] -> | Some new_addr, [] ->
let stack = AliasingDomain.add access_var new_loc astate.stack in let stack = AliasingDomain.add access_var new_addr astate.stack in
Ok ({astate with stack}, new_loc) Ok ({astate with stack}, new_addr)
| None, _ | Some _, _ :: _ -> | None, _ | Some _, _ :: _ ->
let astate, base_loc = let astate, base_addr =
match AliasingDomain.find_opt access_var astate.stack with match AliasingDomain.find_opt access_var astate.stack with
| Some loc -> | Some addr ->
(astate, loc) (astate, addr)
| None -> | None ->
let loc = AbstractLocation.mk_fresh () in let addr = AbstractAddress.mk_fresh () in
let stack = AliasingDomain.add access_var loc astate.stack in let stack = AliasingDomain.add access_var addr astate.stack in
({astate with stack}, loc) ({astate with stack}, addr)
in in
walk ~overwrite_last base_loc access_list astate let actor = {access_expr; location} in
walk actor ~overwrite_last base_addr access_list astate
(** Use the stack and heap to walk the access path represented by the given expression down to an (** Use the stack and heap to walk the access path represented by the given expression down to an
abstract location representing what the expression points to. abstract address representing what the expression points to.
Return an error state if it traverses some known invalid location or if the end destination is Return an error state if it traverses some known invalid address or if the end destination is
known to be invalid. *) known to be invalid. *)
let materialize_location astate access_expr = walk_access_expr astate access_expr let materialize_address astate access_expr = walk_access_expr astate access_expr
(** Use the stack and heap to walk the access path represented by the given expression down to an (** Use the stack and heap to walk the access path represented by the given expression down to an
abstract location representing what the expression points to, and replace that with the given abstract address representing what the expression points to, and replace that with the given
location. address.
Return an error state if it traverses some known invalid location. *) Return an error state if it traverses some known invalid address. *)
let overwrite_location astate access_expr new_loc = let overwrite_address astate access_expr new_addr =
walk_access_expr ~overwrite_last:new_loc astate access_expr walk_access_expr ~overwrite_last:new_addr astate access_expr
(** Add the given location to the set of know invalid locations. *) (** Add the given address to the set of know invalid addresses. *)
let mark_invalid loc astate = let mark_invalid actor address astate =
{astate with invalids= AbstractLocationsDomain.add loc astate.invalids} {astate with invalids= InvalidAddressesDomain.add address actor astate.invalids}
let read access_expr astate = let read location access_expr astate =
materialize_location astate access_expr materialize_address astate access_expr location
>>= fun (astate, loc) -> check_loc_access loc astate >>| fun astate -> (astate, loc) >>= fun (astate, addr) ->
let actor = {access_expr; location} in
check_addr_access actor addr astate >>| fun astate -> (astate, addr)
let read_all access_exprs astate = let read_all location access_exprs astate =
List.fold_result access_exprs ~init:astate ~f:(fun astate access_expr -> List.fold_result access_exprs ~init:astate ~f:(fun astate access_expr ->
read access_expr astate >>| fst ) read location access_expr astate >>| fst )
let write access_expr loc astate = let write location access_expr addr astate =
overwrite_location astate access_expr loc >>| fun (astate, _) -> astate overwrite_address astate access_expr addr location >>| fun (astate, _) -> astate
let invalidate access_expr astate = let invalidate location access_expr astate =
materialize_location astate access_expr materialize_address astate access_expr location
>>= fun (astate, loc) -> check_loc_access loc astate >>| mark_invalid loc >>= fun (astate, addr) ->
let actor = {access_expr; location} in
check_addr_access actor addr astate >>| mark_invalid actor addr

@ -8,7 +8,7 @@
open! IStd open! IStd
module F = Format module F = Format
module AbstractLocation : sig module AbstractAddress : sig
type t = private int [@@deriving compare] type t = private int [@@deriving compare]
val mk_fresh : unit -> t val mk_fresh : unit -> t
@ -22,27 +22,25 @@ module Access : sig
val pp : F.formatter -> t -> unit val pp : F.formatter -> t -> unit
end end
module AbstractLocationDomain : AbstractDomain.S with type astate = AbstractLocation.t module AbstractAddressDomain : AbstractDomain.S with type astate = AbstractAddress.t
module AbstractLocationsDomain : module type of AbstractDomain.FiniteSet (AbstractLocation) module MemoryEdges : module type of AbstractDomain.InvertedMap (Access) (AbstractAddressDomain)
module MemoryEdges : module type of AbstractDomain.InvertedMap (Access) (AbstractLocationDomain) module MemoryDomain : module type of AbstractDomain.InvertedMap (AbstractAddress) (MemoryEdges)
module MemoryDomain : module type of AbstractDomain.InvertedMap (AbstractLocation) (MemoryEdges) module AliasingDomain : module type of AbstractDomain.InvertedMap (Var) (AbstractAddressDomain)
module AliasingDomain : module type of AbstractDomain.InvertedMap (Var) (AbstractLocationDomain) module InvalidAddressesDomain : AbstractDomain.S
module InvalidLocationsDomain : module type of AbstractLocationsDomain
type t = type t =
{ heap: MemoryDomain.astate { heap: MemoryDomain.astate
(** Symbolic representation of the heap: a graph where nodes are abstract locations and edges are (** Symbolic representation of the heap: a graph where nodes are abstract addresses and edges are
access path elements. *) access path elements. *)
; stack: AliasingDomain.astate ; stack: AliasingDomain.astate
(** Symbolic representation of the stack: which memory location do variables point to. No other (** Symbolic representation of the stack: which memory address do variables point to. No other
values are being tracked. *) values are being tracked. *)
; invalids: InvalidLocationsDomain.astate ; invalids: InvalidAddressesDomain.astate
(** Set of locations known to be in an invalid state. *) } (** Set of addresses known to be in an invalid state. *) }
include AbstractDomain.S with type astate = t include AbstractDomain.S with type astate = t
@ -51,15 +49,21 @@ val initial : t
module Diagnostic : sig module Diagnostic : sig
type t type t
val to_string : t -> string val get_message : t -> string
val get_location : t -> Location.t
val get_issue_type : t -> IssueType.t
val get_trace : t -> Errlog.loc_trace
end end
type 'a access_result = ('a, t * Diagnostic.t) result type 'a access_result = ('a, t * Diagnostic.t) result
val read : AccessExpression.t -> t -> (t * AbstractLocation.t) access_result val read : Location.t -> AccessExpression.t -> t -> (t * AbstractAddress.t) access_result
val read_all : AccessExpression.t list -> t -> t access_result val read_all : Location.t -> AccessExpression.t list -> t -> t access_result
val write : AccessExpression.t -> AbstractLocation.t -> t -> t access_result val write : Location.t -> AccessExpression.t -> AbstractAddress.t -> t -> t access_result
val invalidate : AccessExpression.t -> t -> t access_result val invalidate : Location.t -> AccessExpression.t -> t -> t access_result

@ -8,7 +8,8 @@ open! IStd
open Result.Monad_infix open Result.Monad_infix
type exec_fun = type exec_fun =
ret:Var.t * Typ.t Location.t
-> ret:Var.t * Typ.t
-> actuals:HilExp.t list -> actuals:HilExp.t list
-> PulseDomain.t -> PulseDomain.t
-> PulseDomain.t PulseDomain.access_result -> PulseDomain.t PulseDomain.access_result
@ -17,10 +18,10 @@ type model = exec_fun
module Cplusplus = struct module Cplusplus = struct
let delete : model = let delete : model =
fun ~ret:_ ~actuals astate -> fun location ~ret:_ ~actuals astate ->
match actuals with match actuals with
| [AccessExpression deleted_access] -> | [AccessExpression deleted_access] ->
PulseDomain.invalidate deleted_access astate PulseDomain.invalidate location deleted_access astate
| _ -> | _ ->
Ok astate Ok astate
end end
@ -38,20 +39,20 @@ module StdVector = struct
let at : model = let at : model =
fun ~ret ~actuals astate -> fun location ~ret ~actuals astate ->
match actuals with match actuals with
| [AccessExpression vector; _index] -> | [AccessExpression vector; _index] ->
PulseDomain.read (deref_internal_array vector) astate PulseDomain.read location (deref_internal_array vector) astate
>>= fun (astate, loc) -> PulseDomain.write (AccessExpression.Base ret) loc astate >>= fun (astate, loc) -> PulseDomain.write location (AccessExpression.Base ret) loc astate
| _ -> | _ ->
Ok astate Ok astate
let push_back : model = let push_back : model =
fun ~ret:_ ~actuals astate -> fun location ~ret:_ ~actuals astate ->
match actuals with match actuals with
| [AccessExpression vector; _value] -> | [AccessExpression vector; _value] ->
PulseDomain.invalidate (deref_internal_array vector) astate PulseDomain.invalidate location (deref_internal_array vector) astate
| _ -> | _ ->
Ok astate Ok astate
end end

@ -7,7 +7,8 @@
open! IStd open! IStd
type exec_fun = type exec_fun =
ret:Var.t * Typ.t Location.t
-> ret:Var.t * Typ.t
-> actuals:HilExp.t list -> actuals:HilExp.t list
-> PulseDomain.t -> PulseDomain.t
-> PulseDomain.t PulseDomain.access_result -> PulseDomain.t PulseDomain.access_result

@ -1,13 +1,13 @@
codetoanalyze/cpp/ownership/returns.cpp, returns::return_deleted_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/returns.cpp, returns::return_deleted_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `x` here,accessed `x` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_branch_bad, 5, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_branch_bad, 5, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_loop_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_loop_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, deref_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, deref_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, double_delete_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, double_delete_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_delete_abort_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_delete_abort_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_delete_throw_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_delete_throw_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_exit_abort_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, gated_exit_abort_ok, 6, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, reassign_field_of_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, reassign_field_of_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s->f` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, return_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, return_deleted_bad, 3, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_branch_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_branch_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s` here]
codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_loop_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_loop_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `s` here,accessed `s->f` here]
codetoanalyze/cpp/pulse/vector.cpp, deref_vector_element_after_lifetime_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [] codetoanalyze/cpp/pulse/vector.cpp, deref_vector_element_after_lifetime_bad, 4, USE_AFTER_LIFETIME, no_bucket, ERROR, [invalidated `&(x).__internal_array[_]` here,accessed `*(y)` here]

Loading…
Cancel
Save