From 6e5d87914bf1f9377038a10a60c7c263a48a5333 Mon Sep 17 00:00:00 2001 From: Sungkeun Cho Date: Fri, 12 Jan 2024 01:47:10 -0800 Subject: [PATCH] [pulse] Avoid destructing artificial variables related to coroutine Summary: This diff avoids destructing the artificial variables that are related to coroutine, `__promise` and `__coro_frame`. https://github.com/llvm/llvm-project/blob/fc6faa1113e9069f41b5500db051210af0eea843/lldb/source/Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.cpp#L38-L39 Before this diff, they were addressed as if local variables, so that they were nullified/destructed when out of scope, which introduced false positives of use-after-lifetime. Reviewed By: ngorogiannis Differential Revision: D52700500 fbshipit-source-id: 1a941acbae735eaa56c635ccedea6daa56978628 --- infer/src/IR/Mangled.ml | 2 ++ infer/src/IR/Mangled.mli | 2 ++ infer/src/IR/Pvar.ml | 2 ++ infer/src/IR/Pvar.mli | 3 +++ infer/src/IR/Var.ml | 2 ++ infer/src/IR/Var.mli | 2 ++ infer/src/backend/preanal.ml | 7 +++++-- infer/src/pulse/Pulse.ml | 4 +++- infer/src/pulse/PulseAbductiveDomain.ml | 2 +- 9 files changed, 22 insertions(+), 4 deletions(-) diff --git a/infer/src/IR/Mangled.ml b/infer/src/IR/Mangled.ml index aa8c6150eed..e6f31688fbd 100644 --- a/infer/src/IR/Mangled.ml +++ b/infer/src/IR/Mangled.ml @@ -41,6 +41,8 @@ let self = from_string "self" let is_self = function {plain= "self"} -> true | _ -> false +let is_artificial = function {plain= "__promise" | "__coro_frame"} -> true | _ -> false + let return_param = from_string "__return_param" let is_return_param = function {plain= "__return_param"} -> true | _ -> false diff --git a/infer/src/IR/Mangled.mli b/infer/src/IR/Mangled.mli index f59932a8c55..1e665da1990 100644 --- a/infer/src/IR/Mangled.mli +++ b/infer/src/IR/Mangled.mli @@ -39,6 +39,8 @@ val self : t [@@warning "-unused-value-declaration"] val is_self : t -> bool +val is_artificial : t -> bool + val return_param : t val is_return_param : t -> bool diff --git a/infer/src/IR/Pvar.ml b/infer/src/IR/Pvar.ml index 85f9d83a5a7..082c2d163e3 100644 --- a/infer/src/IR/Pvar.ml +++ b/infer/src/IR/Pvar.ml @@ -118,6 +118,8 @@ let is_this pvar = Mangled.is_this (get_name pvar) (** Check if a pvar is the special "self" var *) let is_self pvar = Mangled.is_self (get_name pvar) +let is_artificial pvar = Mangled.is_artificial (get_name pvar) + (** Check if the pvar is a return var *) let is_return pv = Mangled.equal (get_name pv) Ident.name_return diff --git a/infer/src/IR/Pvar.mli b/infer/src/IR/Pvar.mli index d01e57c3f69..8dd9fea1eb0 100644 --- a/infer/src/IR/Pvar.mli +++ b/infer/src/IR/Pvar.mli @@ -78,6 +78,9 @@ val is_this : t -> bool val is_self : t -> bool (** Check if a pvar is the special "self" var *) +val is_artificial : t -> bool +(** Check if a pvar is an artificial variable related coroutine, "__promise" or "__coro_frame" *) + val is_frontend_tmp : t -> bool (** return true if [pvar] is a temporary variable generated by the frontend *) diff --git a/infer/src/IR/Var.ml b/infer/src/IR/Var.ml index 80dd942a2d4..61fbb675d2f 100644 --- a/infer/src/IR/Var.ml +++ b/infer/src/IR/Var.ml @@ -47,6 +47,8 @@ let is_none = function LogicalVar id -> Ident.is_none id | _ -> false let is_this = function ProgramVar pv -> Pvar.is_this pv | LogicalVar _ -> false +let is_artificial = function ProgramVar pv -> Pvar.is_artificial pv | LogicalVar _ -> false + let get_all_vars_in_exp e = let acc = Exp.free_vars e |> Sequence.map ~f:of_id in Exp.program_vars e |> Sequence.map ~f:of_pvar |> Sequence.append acc diff --git a/infer/src/IR/Var.mli b/infer/src/IR/Var.mli index eceb5ab73d2..a98848c7c3d 100644 --- a/infer/src/IR/Var.mli +++ b/infer/src/IR/Var.mli @@ -42,6 +42,8 @@ val is_none : t -> bool val is_this : t -> bool +val is_artificial : t -> bool + val appears_in_source_code : t -> bool (** return true if this variable appears in source code (i.e., is not a LogicalVar or a frontend-generated ProgramVar) *) diff --git a/infer/src/backend/preanal.ml b/infer/src/backend/preanal.ml index 40d75233fba..81393746453 100644 --- a/infer/src/backend/preanal.ml +++ b/infer/src/backend/preanal.ml @@ -381,7 +381,9 @@ module Liveness = struct let is_local pvar = not (Liveness.is_always_in_scope proc_desc pvar) in let prepend_node_nullify_instructions loc pvars instrs = List.fold pvars ~init:instrs ~f:(fun instrs pvar -> - if is_local pvar then Sil.Metadata (Nullify (pvar, loc)) :: instrs else instrs ) + if is_local pvar && not (Pvar.is_artificial pvar) then + Sil.Metadata (Nullify (pvar, loc)) :: instrs + else instrs ) in let node_deadvars_instruction loc vars = let local_vars = @@ -399,6 +401,7 @@ module Liveness = struct let dead_vars, pvars_to_nullify = VarDomain.fold (fun var (dead_vars, pvars_to_nullify) -> + let dead_vars = if Var.is_artificial var then dead_vars else var :: dead_vars in let pvars_to_nullify = match Var.get_pvar var with | Some pvar when not (AddressTaken.Domain.mem pvar address_taken_vars) -> @@ -408,7 +411,7 @@ module Liveness = struct | _ -> pvars_to_nullify in - (var :: dead_vars, pvars_to_nullify) ) + (dead_vars, pvars_to_nullify) ) to_nullify ([], []) in let loc = Procdesc.Node.get_last_loc node in diff --git a/infer/src/pulse/Pulse.ml b/infer/src/pulse/Pulse.ml index 23d2cfeb6fb..895e634df78 100644 --- a/infer/src/pulse/Pulse.ml +++ b/infer/src/pulse/Pulse.ml @@ -310,7 +310,9 @@ module PulseTransferFunctions = struct if flags.cf_injected_destructor then match (callee_pname, actuals) with | Some (Procname.ObjC_Cpp pname), [(Exp.Lvar pvar, typ)] - when Pvar.is_local pvar && not (Procname.ObjC_Cpp.is_inner_destructor pname) -> + when Pvar.is_local pvar + && (not (Procname.ObjC_Cpp.is_inner_destructor pname)) + && not (Pvar.is_artificial pvar) -> (* ignore inner destructors, only trigger out of scope on the final destructor call *) Some (pvar, typ) | _ -> diff --git a/infer/src/pulse/PulseAbductiveDomain.ml b/infer/src/pulse/PulseAbductiveDomain.ml index c287694d2a1..54e1977bf90 100644 --- a/infer/src/pulse/PulseAbductiveDomain.ml +++ b/infer/src/pulse/PulseAbductiveDomain.ml @@ -972,7 +972,7 @@ module Internal = struct else None ) in match var with - | Var.ProgramVar pvar -> + | Var.ProgramVar pvar when not (Pvar.is_artificial pvar) -> get_local_typ_opt pvar |> Option.value_map ~default:acc ~f:(add_out_of_scope_attribute addr pvar location history acc)