From fa220f58f02014e4a3389f429b82948a09dc4986 Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Fri, 9 Aug 2013 00:55:47 +0000 Subject: [PATCH] [analyzer] Warn when using 'delete' on an uninitialized variable. Patch by Karthik Bhat, modified slightly by me. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188043 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Checkers/CallAndMessageChecker.cpp | 30 ++++++++++++++++- test/Analysis/NewDelete-checker-test.cpp | 32 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index c3c5b5e087..976dcaabf6 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -28,13 +28,16 @@ using namespace ento; namespace { class CallAndMessageChecker - : public Checker< check::PreStmt, check::PreObjCMessage, + : public Checker< check::PreStmt, + check::PreStmt, + check::PreObjCMessage, check::PreCall > { mutable OwningPtr BT_call_null; mutable OwningPtr BT_call_undef; mutable OwningPtr BT_cxx_call_null; mutable OwningPtr BT_cxx_call_undef; mutable OwningPtr BT_call_arg; + mutable OwningPtr BT_cxx_delete_undef; mutable OwningPtr BT_msg_undef; mutable OwningPtr BT_objc_prop_undef; mutable OwningPtr BT_objc_subscript_undef; @@ -44,6 +47,7 @@ class CallAndMessageChecker public: void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; + void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const; void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; @@ -250,6 +254,30 @@ void CallAndMessageChecker::checkPreStmt(const CallExpr *CE, C.addTransition(StNonNull); } +void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE, + CheckerContext &C) const { + + SVal Arg = C.getSVal(DE->getArgument()); + if (Arg.isUndef()) { + StringRef Desc; + ExplodedNode *N = C.generateSink(); + if (!N) + return; + if (!BT_cxx_delete_undef) + BT_cxx_delete_undef.reset(new BuiltinBug("Uninitialized argument value")); + if (DE->isArrayFormAsWritten()) + Desc = "Argument to 'delete[]' is uninitialized"; + else + Desc = "Argument to 'delete' is uninitialized"; + BugType *BT = BT_cxx_delete_undef.get(); + BugReport *R = new BugReport(*BT, Desc, N); + bugreporter::trackNullOrUndefValue(N, DE, *R); + C.emitReport(R); + return; + } +} + + void CallAndMessageChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); diff --git a/test/Analysis/NewDelete-checker-test.cpp b/test/Analysis/NewDelete-checker-test.cpp index 83796357b4..442b8fbef0 100644 --- a/test/Analysis/NewDelete-checker-test.cpp +++ b/test/Analysis/NewDelete-checker-test.cpp @@ -4,6 +4,7 @@ typedef __typeof__(sizeof(int)) size_t; extern "C" void *malloc(size_t); +extern "C" void free (void* ptr); int *global; //------------------ @@ -207,6 +208,37 @@ void testConstEscapePlacementNew() { escapeVoidPtr(y); } // no-warning +//============== Test Uninitialized delete delete[]======================== +void testUninitDelete() { + int *x; + int * y = new int; + delete y; + delete x; // expected-warning{{Argument to 'delete' is uninitialized}} +} + +void testUninitDeleteArray() { + int *x; + int * y = new int[5]; + delete[] y; + delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} +} + +void testUninitFree() { + int *x; + free(x); // expected-warning{{Function call argument is an uninitialized value}} +} + +void testUninitDeleteSink() { + int *x; + delete x; // expected-warning{{Argument to 'delete' is uninitialized}} + (*(volatile int *)0 = 1); // no warn +} + +void testUninitDeleteArraySink() { + int *x; + delete[] x; // expected-warning{{Argument to 'delete[]' is uninitialized}} + (*(volatile int *)0 = 1); // no warn +} namespace reference_count { class control_block { -- 2.40.0