]> granicus.if.org Git - clang/commitdiff
[analyzer] Warn when using 'delete' on an uninitialized variable.
authorJordan Rose <jordan_rose@apple.com>
Fri, 9 Aug 2013 00:55:47 +0000 (00:55 +0000)
committerJordan Rose <jordan_rose@apple.com>
Fri, 9 Aug 2013 00:55:47 +0000 (00:55 +0000)
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

lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
test/Analysis/NewDelete-checker-test.cpp

index c3c5b5e087f48581ebfde8262f3e06c9b292b584..976dcaabf660dd7764102b8c0c256bcbc0c251b4 100644 (file)
@@ -28,13 +28,16 @@ using namespace ento;
 
 namespace {
 class CallAndMessageChecker
-  : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage,
+  : public Checker< check::PreStmt<CallExpr>,
+                    check::PreStmt<CXXDeleteExpr>,
+                    check::PreObjCMessage,
                     check::PreCall > {
   mutable OwningPtr<BugType> BT_call_null;
   mutable OwningPtr<BugType> BT_call_undef;
   mutable OwningPtr<BugType> BT_cxx_call_null;
   mutable OwningPtr<BugType> BT_cxx_call_undef;
   mutable OwningPtr<BugType> BT_call_arg;
+  mutable OwningPtr<BugType> BT_cxx_delete_undef;
   mutable OwningPtr<BugType> BT_msg_undef;
   mutable OwningPtr<BugType> BT_objc_prop_undef;
   mutable OwningPtr<BugType> 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();
index 83796357b4c3cbae783f966baa4fb842838e418c..442b8fbef09a494d74277808a5e6af29973e935a 100644 (file)
@@ -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 {