Index: lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -33,8 +33,8 @@ enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted }; - void reportOOB(CheckerContext &C, ProgramStateRef errorState, - OOB_Kind kind) const; + void reportOOB(CheckerContext &C, ProgramStateRef errorState, OOB_Kind kind, + std::unique_ptr Visitor = nullptr) const; public: void checkLocation(SVal l, bool isLoad, const Stmt*S, @@ -205,8 +205,10 @@ // 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_Tainted); + SVal ByteOffset = rawOffset.getByteOffset(); + if (state->isTainted(ByteOffset)) { + reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted, + llvm::make_unique(ByteOffset)); return; } } else if (state_exceedsUpperBound) { @@ -226,9 +228,9 @@ checkerContext.addTransition(state); } -void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, - ProgramStateRef errorState, - OOB_Kind kind) const { +void ArrayBoundCheckerV2::reportOOB( + CheckerContext &checkerContext, ProgramStateRef errorState, OOB_Kind kind, + std::unique_ptr Visitor) const { ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState); if (!errorNode) @@ -255,8 +257,11 @@ break; } - checkerContext.emitReport( - llvm::make_unique(*BT, os.str(), errorNode)); + auto BR = llvm::make_unique(*BT, os.str(), errorNode); + if (Visitor) + BR->addVisitor(std::move(Visitor)); + + checkerContext.emitReport(std::move(BR)); } #ifndef NDEBUG Index: lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -24,22 +24,25 @@ namespace { class DivZeroChecker : public Checker< check::PreStmt > { mutable std::unique_ptr BT; - void reportBug(const char *Msg, - ProgramStateRef StateZero, - CheckerContext &C) const ; + void reportBug(const char *Msg, ProgramStateRef StateZero, CheckerContext &C, + std::unique_ptr Visitor = nullptr) const; + public: void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; }; } // end anonymous namespace -void DivZeroChecker::reportBug(const char *Msg, - ProgramStateRef StateZero, - CheckerContext &C) const { +void DivZeroChecker::reportBug( + const char *Msg, ProgramStateRef StateZero, CheckerContext &C, + std::unique_ptr Visitor) const { if (ExplodedNode *N = C.generateErrorNode(StateZero)) { if (!BT) BT.reset(new BuiltinBug(this, "Division by zero")); auto R = llvm::make_unique(*BT, Msg, N); + if (Visitor) + R->addVisitor(std::move(Visitor)); + bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R); C.emitReport(std::move(R)); } @@ -78,7 +81,8 @@ bool TaintedD = C.getState()->isTainted(*DV); if ((stateNotZero && stateZero && TaintedD)) { - reportBug("Division by a tainted value, possibly zero", stateZero, C); + reportBug("Division by a tainted value, possibly zero", stateZero, C, + llvm::make_unique(*DV)); return; } Index: lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -32,19 +32,18 @@ mutable std::unique_ptr BT; enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Tainted, VLA_Negative }; - void reportBug(VLASize_Kind Kind, - const Expr *SizeE, - ProgramStateRef State, - CheckerContext &C) const; + void reportBug(VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, + CheckerContext &C, + std::unique_ptr Visitor = nullptr) const; + public: void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; }; } // end anonymous namespace -void VLASizeChecker::reportBug(VLASize_Kind Kind, - const Expr *SizeE, - ProgramStateRef State, - CheckerContext &C) const { +void VLASizeChecker::reportBug( + VLASize_Kind Kind, const Expr *SizeE, ProgramStateRef State, + CheckerContext &C, std::unique_ptr Visitor) const { // Generate an error node. ExplodedNode *N = C.generateErrorNode(State); if (!N) @@ -73,6 +72,7 @@ } auto report = llvm::make_unique(*BT, os.str(), N); + report->addVisitor(std::move(Visitor)); report->addRange(SizeE->getSourceRange()); bugreporter::trackNullOrUndefValue(N, SizeE, *report); C.emitReport(std::move(report)); @@ -108,7 +108,8 @@ // Check if the size is tainted. if (state->isTainted(sizeV)) { - reportBug(VLA_Tainted, SE, nullptr, C); + reportBug(VLA_Tainted, SE, nullptr, C, + llvm::make_unique(sizeV)); return; } Index: test/Analysis/taint-diagnostic-visitor.c =================================================================== --- test/Analysis/taint-diagnostic-visitor.c +++ test/Analysis/taint-diagnostic-visitor.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core -analyzer-output=text -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.security.taint,core,alpha.security.ArrayBoundV2 -analyzer-output=text -verify %s // This file is for testing enhanced diagnostics produced by the GenericTaintChecker @@ -11,3 +11,26 @@ scanf("%s", buf); // expected-note {{Taint originated here}} system(buf); // expected-warning {{Untrusted data is passed to a system call}} // expected-note {{Untrusted data is passed to a system call (CERT/STR02-C. Sanitize data passed to complex subsystems)}} } + +int taintDiagnosticOutOfBound() { + int index; + int Array[] = {1, 2, 3, 4, 5}; + scanf("%d", &index); // expected-note {{Taint originated here}} + return Array[index]; // expected-warning {{Out of bound memory access (index is tainted)}} + // expected-note@-1 {{Out of bound memory access (index is tainted)}} +} + +int taintDiagnosticDivZero(int operand) { + scanf("%d", &operand); // expected-note {{Value assigned to 'operand'}} + // expected-note@-1 {{Taint originated here}} + return 10 / operand; // expected-warning {{Division by a tainted value, possibly zero}} + // expected-note@-1 {{Division by a tainted value, possibly zero}} +} + +void taintDiagnosticVLA() { + int x; + scanf("%d", &x); // expected-note {{Value assigned to 'x'}} + // expected-note@-1 {{Taint originated here}} + int vla[x]; // expected-warning {{Declared variable-length array (VLA) has tainted size}} + // expected-note@-1 {{Declared variable-length array (VLA) has tainted size}} +}