aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2012-01-11 08:13:21 +0000
committerTed Kremenek <kremenek@apple.com>2012-01-11 08:13:21 +0000
commit3e97758f22f31d0dbc336fc4794b86aed8607053 (patch)
treea5fedfb9ad7984a1f0536719273d5e28388ae629 /lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
parentcb28b48fec2ed89c918775d107dc639be837e9eb (diff)
"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! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147931 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp109
1 files changed, 61 insertions, 48 deletions
diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 420acd5aac..ffe23f14b1 100644
--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -39,6 +39,8 @@ public:
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 @@ private:
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 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,
}
//===----------------------------------------------------------------------===//
-// "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 @@ static bool IsZeroByteAllocation(const ProgramState *state,
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 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
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 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
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 @@ void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
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 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
.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)