[cfe-commits] r147931 - in /cfe/trunk: lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp test/Analysis/unix-fns.c
Ted Kremenek
kremenek at apple.com
Wed Jan 11 00:13:21 PST 2012
Author: kremenek
Date: Wed Jan 11 02:13:21 2012
New Revision: 147931
URL: http://llvm.org/viewvc/llvm-project?rev=147931&view=rev
Log:
"This change adds alloca/valloc checks to UnixAPIChecker. It includes a small refactoring for
the common *alloc functions as well as a few tiny wibbles (adds a note
to CWE/CERT advisory numbers in the bug output, and fixes a couple
80-column-wide violations.)"
Patch by Austin Seipp!
Modified:
cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
cfe/trunk/test/Analysis/unix-fns.c
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp?rev=147931&r1=147930&r2=147931&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp Wed Jan 11 02:13:21 2012
@@ -39,6 +39,8 @@
void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const;
+ void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const;
typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,
const CallExpr *) const;
@@ -47,6 +49,11 @@
const ProgramState *falseState,
const Expr *arg,
const char *fn_name) const;
+ void BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const;
};
} //end anonymous namespace
@@ -178,8 +185,10 @@
}
//===----------------------------------------------------------------------===//
-// "calloc", "malloc" and "realloc" with allocation size 0
+// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0
//===----------------------------------------------------------------------===//
+// FIXME: Eventually these should be rolled into the MallocChecker, but right now
+// they're more basic and valuable for widespread use.
// Returns true if we try to do a zero byte allocation, false otherwise.
// Fills in trueState and falseState.
@@ -187,7 +196,9 @@
const SVal argVal,
const ProgramState **trueState,
const ProgramState **falseState) {
- llvm::tie(*trueState, *falseState) = state->assume(cast<DefinedSVal>(argVal));
+ llvm::tie(*trueState, *falseState) =
+ state->assume(cast<DefinedSVal>(argVal));
+
return (*falseState && !*trueState);
}
@@ -202,9 +213,8 @@
if (!N)
return false;
- // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
- // output.
- LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");
+ LazyInitialize(BT_mallocZero,
+ "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
llvm::SmallString<256> S;
llvm::raw_svector_ostream os(S);
@@ -218,6 +228,37 @@
return true;
}
+// Does a basic check for 0-sized allocations suitable for most of the below
+// functions (modulo "calloc")
+void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
+ const CallExpr *CE,
+ const unsigned numArgs,
+ const unsigned sizeArg,
+ const char *fn) const {
+ // Sanity check for the correct number of arguments
+ if (CE->getNumArgs() != numArgs)
+ return;
+
+ // Check if the allocation size is 0.
+ const ProgramState *state = C.getState();
+ const ProgramState *trueState = NULL, *falseState = NULL;
+ const Expr *arg = CE->getArg(sizeArg);
+ SVal argVal = state->getSVal(arg, C.getLocationContext());
+
+ if (argVal.isUnknownOrUndef())
+ return;
+
+ // Is the value perfectly constrained to zero?
+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
+ (void) ReportZeroByteAllocation(C, falseState, arg, fn);
+ return;
+ }
+ // Assume the the value is non-zero going forward.
+ assert(trueState);
+ if (trueState != state)
+ C.addTransition(trueState);
+}
+
void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
const CallExpr *CE) const {
unsigned int nArgs = CE->getNumArgs();
@@ -254,63 +295,33 @@
C.addTransition(trueState);
}
-// FIXME: Eventually this should be rolled into the MallocChecker, but this
-// check is more basic and is valuable for widespread use.
void UnixAPIChecker::CheckMallocZero(CheckerContext &C,
const CallExpr *CE) const {
- // Sanity check that malloc takes one argument.
- if (CE->getNumArgs() != 1)
- return;
-
- // Check if the allocation size is 0.
- const ProgramState *state = C.getState();
- const ProgramState *trueState = NULL, *falseState = NULL;
- const Expr *arg = CE->getArg(0);
- SVal argVal = state->getSVal(arg, C.getLocationContext());
-
- if (argVal.isUnknownOrUndef())
- return;
-
- // Is the value perfectly constrained to zero?
- if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
- (void) ReportZeroByteAllocation(C, falseState, arg, "malloc");
- return;
- }
- // Assume the the value is non-zero going forward.
- assert(trueState);
- if (trueState != state)
- C.addTransition(trueState);
+ BasicAllocationCheck(C, CE, 1, 0, "malloc");
}
void UnixAPIChecker::CheckReallocZero(CheckerContext &C,
const CallExpr *CE) const {
- if (CE->getNumArgs() != 2)
- return;
+ BasicAllocationCheck(C, CE, 2, 1, "realloc");
+}
- const ProgramState *state = C.getState();
- const ProgramState *trueState = NULL, *falseState = NULL;
- const Expr *arg = CE->getArg(1);
- SVal argVal = state->getSVal(arg, C.getLocationContext());
+void UnixAPIChecker::CheckAllocaZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "alloca");
+}
- if (argVal.isUnknownOrUndef())
- return;
+void UnixAPIChecker::CheckVallocZero(CheckerContext &C,
+ const CallExpr *CE) const {
+ BasicAllocationCheck(C, CE, 1, 0, "valloc");
+}
- if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
- ReportZeroByteAllocation(C, falseState, arg, "realloc");
- return;
- }
- // Assume the the value is non-zero going forward.
- assert(trueState);
- if (trueState != state)
- C.addTransition(trueState);
-}
-
//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
+void UnixAPIChecker::checkPreStmt(const CallExpr *CE,
+ CheckerContext &C) const {
StringRef FName = C.getCalleeName(CE);
if (FName.empty())
return;
@@ -322,6 +333,8 @@
.Case("calloc", &UnixAPIChecker::CheckCallocZero)
.Case("malloc", &UnixAPIChecker::CheckMallocZero)
.Case("realloc", &UnixAPIChecker::CheckReallocZero)
+ .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero)
+ .Case("valloc", &UnixAPIChecker::CheckVallocZero)
.Default(NULL);
if (SC)
Modified: cfe/trunk/test/Analysis/unix-fns.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/unix-fns.c?rev=147931&r1=147930&r2=147931&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/unix-fns.c (original)
+++ cfe/trunk/test/Analysis/unix-fns.c Wed Jan 11 02:13:21 2012
@@ -12,6 +12,8 @@
void *calloc(size_t, size_t);
void *malloc(size_t);
void *realloc(void *, size_t);
+void *alloca(size_t);
+void *valloc(size_t);
typedef void (^dispatch_block_t)(void);
typedef long dispatch_once_t;
@@ -98,3 +100,39 @@
foo[i] = 0;
}
}
+void test_alloca() {
+ char *foo = alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_alloca_nowarn(size_t sz) {
+ char *foo = alloca(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_builtin_alloca() {
+ char *foo2 = __builtin_alloca(0); // expected-warning{{Call to 'alloca' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo2[i] = 0;
+ }
+}
+void test_builtin_alloca_nowarn(size_t sz) {
+ char *foo2 = __builtin_alloca(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo2[i] = 0;
+ }
+}
+void test_valloc() {
+ char *foo = valloc(0); // expected-warning{{Call to 'valloc' has an allocation size of 0 bytes}}
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
+void test_valloc_nowarn(size_t sz) {
+ char *foo = valloc(sz); // no-warning
+ for(unsigned i = 0; i < 100; i++) {
+ foo[i] = 0;
+ }
+}
More information about the cfe-commits
mailing list