diff --git a/infer/src/checkers/Ownership.ml b/infer/src/checkers/Ownership.ml index 64c6c3f9a..9f9d9227e 100644 --- a/infer/src/checkers/Ownership.ml +++ b/infer/src/checkers/Ownership.ml @@ -267,6 +267,18 @@ module TransferFunctions (CFG : ProcCfg.S) = struct (* assign to field, array, indirectly with &/*, or a combination *) Domain.exp_add_reads rhs_exp loc summary astate |> Domain.access_path_add_read (AccessExpression.to_access_path lhs_access_exp) loc summary + | Call (Some (lhs_var, _), Direct callee_pname, actuals, _, _) + when Typ.Procname.equal callee_pname BuiltinDecl.__placement_new -> ( + match + (* placement new creates an alias between lhs_var and placement_var. model as lhs_var + borrowing from placement_var *) + Option.bind ~f:extract_base_var (List.last actuals) + with + | Some (placement_var, _) -> + Domain.add placement_var CapabilityDomain.Owned astate + |> Domain.borrow_vars lhs_var (VarSet.singleton placement_var) + | None -> + astate ) | Call (_, Direct callee_pname, [(AccessExpression Base ((lhs_var, _) as lhs_base))], _, loc) when transfers_ownership callee_pname -> Domain.base_add_read lhs_base loc summary astate diff --git a/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp b/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp index fe315b4f1..c583cf58a 100644 --- a/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp +++ b/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp @@ -113,3 +113,33 @@ class Subclass : virtual POD { */ ~Subclass() { delete f; } }; + +void basic_placement_new_ok() { + S* ptr = new S(1); + S* tptr = new (ptr) S(1); + tptr->~S(); + delete[] ptr; +} + +S* destruct_pointer_contents_then_placement_new1_ok(S* s) { + s->~S(); + new (s) S(1); + return s; +} + +// need better heap abstraction to catch this example and the next +S* FN_placement_new_aliasing1_bad() { + S* s = new S(1); + s->~S(); + auto alias = new (s) S(2); + delete alias; // this deletes s too + return s; // bad, returning freed memory +} + +S* FN_placement_new_aliasing2_bad() { + S* s = new S(1); + s->~S(); + auto alias = new (s) S(2); + delete s; // this deletes alias too + return alias; // bad, returning freed memory +}