diff --git a/infer/src/pulse/Pulse.ml b/infer/src/pulse/Pulse.ml index 0ee0a56f5..95ec959a4 100644 --- a/infer/src/pulse/Pulse.ml +++ b/infer/src/pulse/Pulse.ml @@ -145,8 +145,8 @@ module PulseTransferFunctions = struct if flags.cf_injected_destructor then match (call, actuals) with | ( Direct (Typ.Procname.ObjC_Cpp pname) - , [AccessExpression (*AddressOf (Base _) as *) destroyed_access] ) - when not (Typ.Procname.ObjC_Cpp.is_inner_destructor pname) -> + , [AccessExpression (AddressOf (Base (ProgramVar pvar, _)) as destroyed_access)] ) + when Pvar.is_local pvar && not (Typ.Procname.ObjC_Cpp.is_inner_destructor pname) -> (* ignore inner destructors, only trigger out of scope on the final destructor call *) Some destroyed_access | _ -> diff --git a/infer/tests/codetoanalyze/cpp/pulse/use_after_destructor.cpp b/infer/tests/codetoanalyze/cpp/pulse/use_after_destructor.cpp index b22d73846..bffcfc42c 100644 --- a/infer/tests/codetoanalyze/cpp/pulse/use_after_destructor.cpp +++ b/infer/tests/codetoanalyze/cpp/pulse/use_after_destructor.cpp @@ -259,4 +259,31 @@ bool variable_init_ternary_ok(bool b) { std::string newPath = b ? "" : mk_string(); } +void move_data(POD* from, POD* to); + +struct Moveable { + Moveable() = default; + Moveable(const Moveable&) = delete; // not copyable + + // move constructor + Moveable(Moveable&& that) noexcept { move_data(&that.data, &data); } + + Moveable& operator=(Moveable&& that) noexcept { + this->~Moveable(); + ::new (this) Moveable(std::move(that)); + return *this; + } + + ~Moveable() {} + + Moveable& operator=(const Moveable&) = delete; + + POD data; +}; + +void move_moveable_ok(Moveable& src) { + Moveable x; + x = std::move(src); +} + } // namespace use_after_destructor