[cfe-commits] r119364 - in /cfe/trunk: lib/Checker/UnixAPIChecker.cpp test/Analysis/unix-fns.c

Ted Kremenek kremenek at apple.com
Tue Nov 16 10:47:04 PST 2010


Author: kremenek
Date: Tue Nov 16 12:47:04 2010
New Revision: 119364

URL: http://llvm.org/viewvc/llvm-project?rev=119364&view=rev
Log:
Static analyzer: Catch calls to malloc() with
allocation sizes of 0 bytes.

Fixes PR 2899.

Modified:
    cfe/trunk/lib/Checker/UnixAPIChecker.cpp
    cfe/trunk/test/Analysis/unix-fns.c

Modified: cfe/trunk/lib/Checker/UnixAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Checker/UnixAPIChecker.cpp?rev=119364&r1=119363&r2=119364&view=diff
==============================================================================
--- cfe/trunk/lib/Checker/UnixAPIChecker.cpp (original)
+++ cfe/trunk/lib/Checker/UnixAPIChecker.cpp Tue Nov 16 12:47:04 2010
@@ -28,6 +28,7 @@
   enum SubChecks {
     OpenFn = 0,
     PthreadOnceFn = 1,
+    MallocZero = 2,
     NumChecks
   };
 
@@ -174,6 +175,53 @@
 }
 
 //===----------------------------------------------------------------------===//
+// "malloc" with allocation size 0
+//===----------------------------------------------------------------------===//
+
+// FIXME: Eventually this should be rolled into the MallocChecker, but this
+// check is more basic and is valuable for widespread use.
+static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
+                            const CallExpr *CE, BugType *&BT) {
+
+  // Sanity check that malloc takes one argument.
+  if (CE->getNumArgs() != 1)
+    return;
+
+  // Check if the allocation size is 0.
+  const GRState *state = C.getState();
+  SVal argVal = state->getSVal(CE->getArg(0));
+
+  if (argVal.isUnknownOrUndef())
+    return;
+  
+  const GRState *trueState, *falseState;
+  llvm::tie(trueState, falseState) = state->Assume(cast<DefinedSVal>(argVal));
+  
+  // Is the value perfectly constrained to zero?
+  if (falseState && !trueState) {
+    ExplodedNode *N = C.GenerateSink(falseState);
+    if (!N)
+      return;
+    
+    LazyInitialize(BT, "bad allocation of 0 bytes");
+    
+    EnhancedBugReport *report =
+      new EnhancedBugReport(*BT, "Call to 'malloc' has an allocation size"
+                                 " of 0 bytes", N);
+    report->addRange(CE->getArg(0)->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                              CE->getArg(0));
+    C.EmitReport(report);
+    return;
+  }
+  // Assume the the value is non-zero going forward.
+  assert(trueState);
+  if (trueState != state) {
+    C.addTransition(trueState);
+  }
+}
+  
+//===----------------------------------------------------------------------===//
 // Central dispatch function.
 //===----------------------------------------------------------------------===//
 
@@ -213,9 +261,12 @@
 
   const SubCheck &SC =
     llvm::StringSwitch<SubCheck>(FI->getName())
-      .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn]))
-      .Case("pthread_once", SubCheck(CheckPthreadOnce, this,
-                                     BTypes[PthreadOnceFn]))
+      .Case("open",
+            SubCheck(CheckOpen, this, BTypes[OpenFn]))
+      .Case("pthread_once",
+            SubCheck(CheckPthreadOnce, this, BTypes[PthreadOnceFn]))
+      .Case("malloc",
+            SubCheck(CheckMallocZero, this, BTypes[MallocZero]))
       .Default(SubCheck());
 
   SC.run(C, CE);

Modified: cfe/trunk/test/Analysis/unix-fns.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unix-fns.c?rev=119364&r1=119363&r2=119364&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/unix-fns.c (original)
+++ cfe/trunk/test/Analysis/unix-fns.c Tue Nov 16 12:47:04 2010
@@ -8,6 +8,9 @@
 typedef struct _opaque_pthread_once_t    __darwin_pthread_once_t;
 typedef __darwin_pthread_once_t pthread_once_t;
 int pthread_once(pthread_once_t *, void (*)(void));
+typedef long unsigned int __darwin_size_t;
+typedef __darwin_size_t size_t;
+void *malloc(size_t);
 
 typedef void (^dispatch_block_t)(void);
 typedef long dispatch_once_t;
@@ -50,3 +53,17 @@
   static pthread_once_t pred = {0x30B1BCBA, {0}};
   pthread_once(&pred, test_pthread_once_aux); // no-warning
 }
+
+// PR 2899 - warn of zero-sized allocations to malloc().
+void pr2899() {
+  char* foo = malloc(0); // expected-warning{{Call to 'malloc' has an allocation size of 0 bytes}}
+  for (unsigned i = 0; i < 100; i++) {
+    foo[i] = 0;
+  }
+}
+void pr2899_nowarn(size_t size) {
+  char* foo = malloc(size); // no-warning
+  for (unsigned i = 0; i < 100; i++) {
+    foo[i] = 0;
+  }
+}





More information about the cfe-commits mailing list