aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp76
1 files changed, 49 insertions, 27 deletions
diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index 0308bf5c11..74d4f24348 100644
--- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -26,14 +26,52 @@ using namespace ento;
namespace {
class VLASizeChecker : public Checker< check::PreStmt<DeclStmt> > {
- mutable llvm::OwningPtr<BugType> BT_zero;
- mutable llvm::OwningPtr<BugType> BT_undef;
-
+ mutable llvm::OwningPtr<BugType> BT;
+ enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted };
+
+ void reportBug(VLASize_Kind Kind,
+ const Expr *SizeE,
+ const ProgramState *State,
+ CheckerContext &C) const;
public:
void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
};
} // end anonymous namespace
+void VLASizeChecker::reportBug(VLASize_Kind Kind,
+ const Expr *SizeE,
+ const ProgramState *State,
+ CheckerContext &C) const {
+ // Generate an error node.
+ ExplodedNode *N = C.generateSink(State);
+ if (!N)
+ return;
+
+ if (!BT)
+ BT.reset(new BuiltinBug("Dangerous variable-length array (VLA) declaration"));
+
+ llvm::SmallString<256> buf;
+ llvm::raw_svector_ostream os(buf);
+ os << "Declared variable-length array (VLA) ";
+ switch (Kind) {
+ case VLA_Garbage:
+ os << "uses a garbage value as its size";
+ break;
+ case VLA_Zero:
+ os << "has zero size";
+ break;
+ case VLA_Tainted:
+ os << "has tainted size";
+ break;
+ }
+
+ BugReport *report = new BugReport(*BT, os.str(), N);
+ report->addRange(SizeE->getSourceRange());
+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SizeE));
+ C.EmitReport(report);
+ return;
+}
+
void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (!DS->isSingleDecl())
return;
@@ -53,20 +91,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
SVal sizeV = state->getSVal(SE, C.getLocationContext());
if (sizeV.isUndef()) {
- // Generate an error node.
- ExplodedNode *N = C.generateSink();
- if (!N)
- return;
-
- if (!BT_undef)
- BT_undef.reset(new BuiltinBug("Declared variable-length array (VLA) "
- "uses a garbage value as its size"));
-
- BugReport *report =
- new BugReport(*BT_undef, BT_undef->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
- C.EmitReport(report);
+ reportBug(VLA_Garbage, SE, state, C);
return;
}
@@ -75,6 +100,12 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (sizeV.isUnknown())
return;
+ // Check if the size is tainted.
+ if (state->isTainted(sizeV)) {
+ reportBug(VLA_Tainted, SE, 0, C);
+ return;
+ }
+
// Check if the size is zero.
DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
@@ -82,16 +113,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
if (stateZero && !stateNotZero) {
- ExplodedNode *N = C.generateSink(stateZero);
- if (!BT_zero)
- BT_zero.reset(new BuiltinBug("Declared variable-length array (VLA) has "
- "zero size"));
-
- BugReport *report =
- new BugReport(*BT_zero, BT_zero->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, SE));
- C.EmitReport(report);
+ reportBug(VLA_Zero, SE, stateZero, C);
return;
}