aboutsummaryrefslogtreecommitdiff
path: root/lib/Checker/UnixAPIChecker.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2010-11-16 18:47:04 +0000
committerTed Kremenek <kremenek@apple.com>2010-11-16 18:47:04 +0000
commitb12fbc216f77bd309f8c416834b341ff43325aab (patch)
tree1e7525dc08db692e03cacee61e8f924b2aa1be88 /lib/Checker/UnixAPIChecker.cpp
parent4383e18fc3d79fd536c6992432e180a11bcb657d (diff)
Static analyzer: Catch calls to malloc() with
allocation sizes of 0 bytes. Fixes PR 2899. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119364 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Checker/UnixAPIChecker.cpp')
-rw-r--r--lib/Checker/UnixAPIChecker.cpp57
1 files changed, 54 insertions, 3 deletions
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index de7346d627..58fe93eee4 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -28,6 +28,7 @@ class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
enum SubChecks {
OpenFn = 0,
PthreadOnceFn = 1,
+ MallocZero = 2,
NumChecks
};
@@ -174,6 +175,53 @@ static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
}
//===----------------------------------------------------------------------===//
+// "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 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
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);