[analyzer] Treat stdin as a source of taint.
Some of the test cases do not currently work because the analyzer core
does not seem to call checkers for pre/post DeclRefExpr visits.
(Opened radar://10573500. To be fixed later on.)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146536 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 890a592..7392872 100644
--- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -24,7 +24,8 @@
using namespace ento;
namespace {
-class GenericTaintChecker : public Checker< check::PostStmt<CallExpr> > {
+class GenericTaintChecker : public Checker< check::PostStmt<CallExpr>,
+ check::PostStmt<DeclRefExpr> > {
mutable llvm::OwningPtr<BugType> BT;
void initBugType() const;
@@ -42,8 +43,12 @@
void processFscanf(const CallExpr *CE, CheckerContext &C) const;
void processRetTaint(const CallExpr *CE, CheckerContext &C) const;
+ bool isStdin(const Expr *E, CheckerContext &C) const;
+ bool isStdin(const DeclRefExpr *E, CheckerContext &C) const;
+
public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
+ void checkPostStmt(const DeclRefExpr *DRE, CheckerContext &C) const;
};
}
@@ -77,18 +82,28 @@
// Check and evaluate the call.
if (evalFunction)
(this->*evalFunction)(CE, C);
+}
+void GenericTaintChecker::checkPostStmt(const DeclRefExpr *DRE,
+ CheckerContext &C) const {
+ if (isStdin(DRE, C)) {
+ const ProgramState *NewState = C.getState()->addTaint(DRE);
+ C.addTransition(NewState);
+ }
}
SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
const Expr* Arg,
bool IssueWarning) const {
const ProgramState *State = C.getState();
- SVal AddrVal = State->getSVal(Arg->IgnoreParenCasts());
+ SVal AddrVal = State->getSVal(Arg->IgnoreParens());
- // TODO: Taint is not going to propagate?
- if (AddrVal.isUnknownOrUndef())
+ // TODO: Taint is not going to propagate? Should we ever peel off the casts
+ // IgnoreParenImpCasts()?
+ if (AddrVal.isUnknownOrUndef()) {
+ assert(State->getSVal(Arg->IgnoreParenImpCasts()).isUnknownOrUndef());
return 0;
+ }
Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
@@ -111,7 +126,6 @@
return Val.getAsSymbol();
}
-
void GenericTaintChecker::processScanf(const CallExpr *CE,
CheckerContext &C) const {
const ProgramState *State = C.getState();
@@ -137,7 +151,7 @@
assert(CE->getNumArgs() >= 2);
// Check is the file descriptor is tainted.
- if (!State->isTainted(CE->getArg(0)))
+ if (!State->isTainted(CE->getArg(0)) && !isStdin(CE->getArg(0), C))
return;
// All arguments except for the first two should get taint.
@@ -158,6 +172,30 @@
C.addTransition(NewState);
}
+bool GenericTaintChecker::isStdin(const Expr *E,
+ CheckerContext &C) const {
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ return isStdin(DR, C);
+ return false;
+}
+
+bool GenericTaintChecker::isStdin(const DeclRefExpr *DR,
+ CheckerContext &C) const {
+ const VarDecl *D = dyn_cast_or_null<VarDecl>(DR->getDecl());
+ if (!D)
+ return false;
+
+ D = D->getCanonicalDecl();
+ if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC())
+ if (const PointerType * PtrTy =
+ dyn_cast<PointerType>(D->getType().getTypePtr()))
+ if (PtrTy->getPointeeType() == C.getASTContext().getFILEType())
+ return true;
+
+ return false;
+}
+
+
void ento::registerGenericTaintChecker(CheckerManager &mgr) {
mgr.registerChecker<GenericTaintChecker>();
}