NoQ created this revision. NoQ added reviewers: dcoughlin, xazax.hun, a.sidorin, george.karpenkov, szepet. Herald added subscribers: cfe-commits, rnkovacs, baloghadamsoftware.
When operator `delete[]` receives a sub-expression of array type, it destroys the array correctly. Even if it's multi-dimensional, simply because in this case it's an array of array-type objects and destroying such array would mean properly destroying each object, where the object itself is an array, so properly destroying it means destroying its objects, etc. In this case the AST is saying that the destroyed type is an array type - and we weren't prepared for that. For now there's no actual calling multiple destructors; at least we're trying not to crash. Repository: rC Clang https://reviews.llvm.org/D46146 Files: lib/StaticAnalyzer/Core/ExprEngine.cpp test/Analysis/new.cpp Index: test/Analysis/new.cpp =================================================================== --- test/Analysis/new.cpp +++ test/Analysis/new.cpp @@ -274,6 +274,24 @@ clang_analyzer_eval(true); // expected-warning{{TRUE}} } +void test_array_delete() { + class C { + public: + ~C() {} + }; + + auto c1 = new C[2][3]; + delete[] c1; // no-crash // no-warning + + C c2[4]; + // FIXME: Should warn. + delete[] &c2; // no-crash + + C c3[7][6]; + // FIXME: Should warn. + delete[] &c3; // no-crash +} + void testDeleteNull() { NoReturnDtor *foo = 0; delete foo; // should not call destructor, checked below Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1086,12 +1086,14 @@ // This workaround will just run the first destructor (which will still // invalidate the entire array). CallOpts.IsArrayCtorOrDtor = true; + // Yes, it may even be a multi-dimensional array. + while (const auto *AT = getContext().getAsArrayType(DTy)) + DTy = AT->getElementType(); if (ArgR) ArgR = getStoreManager().GetElementZeroRegion(cast<SubRegion>(ArgR), DTy); } - VisitCXXDestructor(DE->getDestroyedType(), ArgR, DE, /*IsBase=*/false, - Pred, Dst, CallOpts); + VisitCXXDestructor(DTy, ArgR, DE, /*IsBase=*/false, Pred, Dst, CallOpts); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
Index: test/Analysis/new.cpp =================================================================== --- test/Analysis/new.cpp +++ test/Analysis/new.cpp @@ -274,6 +274,24 @@ clang_analyzer_eval(true); // expected-warning{{TRUE}} } +void test_array_delete() { + class C { + public: + ~C() {} + }; + + auto c1 = new C[2][3]; + delete[] c1; // no-crash // no-warning + + C c2[4]; + // FIXME: Should warn. + delete[] &c2; // no-crash + + C c3[7][6]; + // FIXME: Should warn. + delete[] &c3; // no-crash +} + void testDeleteNull() { NoReturnDtor *foo = 0; delete foo; // should not call destructor, checked below Index: lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngine.cpp +++ lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1086,12 +1086,14 @@ // This workaround will just run the first destructor (which will still // invalidate the entire array). CallOpts.IsArrayCtorOrDtor = true; + // Yes, it may even be a multi-dimensional array. + while (const auto *AT = getContext().getAsArrayType(DTy)) + DTy = AT->getElementType(); if (ArgR) ArgR = getStoreManager().GetElementZeroRegion(cast<SubRegion>(ArgR), DTy); } - VisitCXXDestructor(DE->getDestroyedType(), ArgR, DE, /*IsBase=*/false, - Pred, Dst, CallOpts); + VisitCXXDestructor(DTy, ArgR, DE, /*IsBase=*/false, Pred, Dst, CallOpts); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits