public Checker<check::Location> {
mutable llvm::OwningPtr<BuiltinBug> BT;
- enum OOB_Kind { OOB_Precedes, OOB_Excedes };
+ enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
void reportOOB(CheckerContext &C, const ProgramState *errorState,
OOB_Kind kind) const;
// If we are under constrained and the index variables are tainted, report.
if (state_exceedsUpperBound && state_withinUpperBound) {
if (state->isTainted(rawOffset.getByteOffset()))
- reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
+ reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
return;
}
llvm::SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
- os << "Out of bound memory access "
- << (kind == OOB_Precedes ? "(accessed memory precedes memory block)"
- : "(access exceeds upper limit of memory block)");
+ os << "Out of bound memory access ";
+ switch (kind) {
+ case OOB_Precedes:
+ os << "(accessed memory precedes memory block)";
+ break;
+ case OOB_Excedes:
+ os << "(access exceeds upper limit of memory block)";
+ break;
+ case OOB_Tainted:
+ os << "(index is tainted)";
+ break;
+ }
checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode));
}
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;
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;
}
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);
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;
}