[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>();
 }