From 6976181b77a085dd1d504140388c957ff9556116 Mon Sep 17 00:00:00 2001 From: Sam Blackshear Date: Mon, 12 Mar 2018 12:46:50 -0700 Subject: [PATCH] [ownership] special-case frontend-generated inner destructors. Reviewed By: da319 Differential Revision: D7189239 fbshipit-source-id: 7975603 --- infer/src/IR/Typ.ml | 5 ++++ infer/src/IR/Typ.mli | 3 +++ infer/src/checkers/Ownership.ml | 4 +++ .../codetoanalyze/cpp/ownership/issues.exp | 26 +++++++++---------- .../cpp/ownership/use_after_destructor.cpp | 17 ++++++++++++ 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/infer/src/IR/Typ.ml b/infer/src/IR/Typ.ml index 8bae6c64a..ac17175d9 100644 --- a/infer/src/IR/Typ.ml +++ b/infer/src/IR/Typ.ml @@ -762,6 +762,11 @@ module Procname = struct is_objc_dealloc name.method_name + let is_inner_destructor ({method_name} as pname) = + is_destructor pname + && String.is_prefix ~prefix:Config.clang_inner_destructor_prefix method_name + + let is_constexpr = function {kind= CPPConstructor {is_constexpr= true}} -> true | _ -> false let is_cpp_lambda {method_name} = String.is_substring ~substring:"operator()" method_name diff --git a/infer/src/IR/Typ.mli b/infer/src/IR/Typ.mli index f922fdd7b..184b6ba65 100644 --- a/infer/src/IR/Typ.mli +++ b/infer/src/IR/Typ.mli @@ -386,6 +386,9 @@ module Procname : sig val is_destructor : t -> bool (** Check if this is a dealloc method. *) + val is_inner_destructor : t -> bool + (** Check if this is a frontend-generated "inner" destructor (see D5834555/D7189239) *) + val is_constexpr : t -> bool (** Check if this is a constexpr function. *) diff --git a/infer/src/checkers/Ownership.ml b/infer/src/checkers/Ownership.ml index 477cddbd0..64595067d 100644 --- a/infer/src/checkers/Ownership.ml +++ b/infer/src/checkers/Ownership.ml @@ -209,6 +209,10 @@ module TransferFunctions (CFG : ProcCfg.S) = struct match pname with | Typ.Procname.ObjC_Cpp clang_pname -> Typ.Procname.ObjC_Cpp.is_destructor clang_pname + && not + (* Our frontend generates synthetic inner destructors to model invocation of base class + destructors correctly; see D5834555/D7189239 *) + (Typ.Procname.ObjC_Cpp.is_inner_destructor clang_pname) | _ -> false diff --git a/infer/tests/codetoanalyze/cpp/ownership/issues.exp b/infer/tests/codetoanalyze/cpp/ownership/issues.exp index dbe6bd404..0d791033a 100644 --- a/infer/tests/codetoanalyze/cpp/ownership/issues.exp +++ b/infer/tests/codetoanalyze/cpp/ownership/issues.exp @@ -1,13 +1,13 @@ -codetoanalyze/cpp/ownership/closures.cpp, implicit_ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/closures.cpp, reassign_lambda_capture_destroy_invoke_bad, 7, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/closures.cpp, ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_branch_bad, 5, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_loop_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, deref_deleted_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, double_delete_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, reassign_field_of_deleted_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, return_deleted_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_branch_bad, 4, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_loop_bad, 4, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_destructor.cpp, double_destructor_bad, 5, USE_AFTER_LIFETIME, [Use of invalid variable] -codetoanalyze/cpp/ownership/use_after_destructor.cpp, use_after_destructor_bad, 3, USE_AFTER_LIFETIME, [Use of invalid variable] +codetoanalyze/cpp/ownership/closures.cpp, implicit_ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/closures.cpp, reassign_lambda_capture_destroy_invoke_bad, 7, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/closures.cpp, ref_capture_destroy_invoke_bad, 6, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_branch_bad, 5, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, delete_in_loop_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, deref_deleted_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, double_delete_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, reassign_field_of_deleted_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, return_deleted_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_branch_bad, 4, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_delete.cpp, use_in_loop_bad, 4, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_destructor.cpp, double_destructor_bad, 5, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] +codetoanalyze/cpp/ownership/use_after_destructor.cpp, use_after_destructor_bad, 3, USE_AFTER_LIFETIME, ERROR, [Use of invalid variable] diff --git a/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp b/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp index 83f5b2403..fe315b4f1 100644 --- a/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp +++ b/infer/tests/codetoanalyze/cpp/ownership/use_after_destructor.cpp @@ -96,3 +96,20 @@ void destruct_twice_ok() { p = tmp; } // destructor for tmp } // destructor for p runs here, but it's harmless + +class Subclass : virtual POD { + int* f; + Subclass() { f = new int; } + + /** frontend code for this destructor will be: + * ~Subclass: + * __infer_inner_destructor_~Subclass(this) + * __infer_inner_destructor_~POD(this) + * + * __infer_inner_destructor_~Subclass: + * delete f; + * + * We need to be careful not to warn that this has been double-destructed + */ + ~Subclass() { delete f; } +};