]> granicus.if.org Git - clang/commitdiff
[analyzer] Propagate taint through NonLoc to NonLoc casts.
authorAnna Zaks <ganna@apple.com>
Tue, 6 Dec 2011 23:12:27 +0000 (23:12 +0000)
committerAnna Zaks <ganna@apple.com>
Tue, 6 Dec 2011 23:12:27 +0000 (23:12 +0000)
 - Created a new SymExpr type - SymbolCast.
 - SymbolCast is created when we don't know how to simplify a NonLoc to
NonLoc casts.
 - A bit of code refactoring: introduced dispatchCast to have better
code reuse, remove a goto.
 - Updated the test case to showcase the new taint flow.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145985 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
include/clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h
lib/StaticAnalyzer/Core/ProgramState.cpp
lib/StaticAnalyzer/Core/RegionStore.cpp
lib/StaticAnalyzer/Core/SValBuilder.cpp
lib/StaticAnalyzer/Core/SVals.cpp
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
lib/StaticAnalyzer/Core/Store.cpp
lib/StaticAnalyzer/Core/SymbolManager.cpp
test/Analysis/taint-tester.c

index b7b2345503e3d1c1e7fc92431e9cb1d01f241631..bbc5b660d5292282c1626ab303271995a44f506a 100644 (file)
@@ -48,11 +48,13 @@ protected:
   /// The width of the scalar type used for array indices.
   const unsigned ArrayIndexWidth;
 
+  virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
+  virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
+
 public:
   // FIXME: Make these protected again once RegionStoreManager correctly
   // handles loads from different bound value types.
-  virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy) = 0;
-  virtual SVal evalCastFromLoc(Loc val, QualType castTy) = 0;
+  virtual SVal dispatchCast(SVal val, QualType castTy) = 0;
 
 public:
   SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
@@ -243,6 +245,9 @@ public:
   NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
                     const SymExpr *rhs, QualType type);
 
+  /// \brief Create a NonLoc value for cast.
+  NonLoc makeNonLoc(const SymExpr *operand, QualType fromTy, QualType toTy);
+
   nonloc::ConcreteInt makeTruthVal(bool b, QualType type) {
     return nonloc::ConcreteInt(BasicVals.getTruthValue(b, type));
   }
index 698a05adad9b406b026b78e32c79657e6877284a..a6005ffd96b8fa997c60dc4bc058e003d6d5be30 100644 (file)
@@ -299,6 +299,7 @@ public:
   }
 };
 
+/// \brief Value representing integer constant.
 class ConcreteInt : public NonLoc {
 public:
   explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
index e4bbf6766dedd400703008016c9500f2d7c9ce9a..addc0d398836b719ec63772c599669260adf5672 100644 (file)
@@ -48,7 +48,7 @@ public:
               MetadataKind,
               BEGIN_SYMBOLS = RegionValueKind,
               END_SYMBOLS = MetadataKind,
-              SymIntKind, SymSymKind };
+              SymIntKind, SymSymKind, CastSymbolKind };
 private:
   Kind K;
 
@@ -276,6 +276,42 @@ public:
   }
 };
 
+/// \brief Represents a cast expression.
+class SymbolCast : public SymExpr {
+  const SymExpr *Operand;
+  /// Type of the operand.
+  QualType FromTy;
+  /// The type of the result.
+  QualType ToTy;
+
+public:
+  SymbolCast(const SymExpr *In, QualType From, QualType To) :
+    SymExpr(CastSymbolKind), Operand(In), FromTy(From), ToTy(To) { }
+
+  QualType getType(ASTContext &C) const { return ToTy; }
+
+  const SymExpr *getOperand() const { return Operand; };
+
+  void dumpToStream(raw_ostream &os) const;
+
+  static void Profile(llvm::FoldingSetNodeID& ID,
+                      const SymExpr *In, QualType From, QualType To) {
+    ID.AddInteger((unsigned) CastSymbolKind);
+    ID.AddPointer(In);
+    ID.Add(From);
+    ID.Add(To);
+  }
+
+  void Profile(llvm::FoldingSetNodeID& ID) {
+    Profile(ID, Operand, FromTy, ToTy);
+  }
+
+  // Implement isa<T> support.
+  static inline bool classof(const SymExpr *SE) {
+    return SE->getKind() == CastSymbolKind;
+  }
+};
+
 /// SymIntExpr - Represents symbolic expression like 'x' + 3.
 class SymIntExpr : public SymExpr {
   const SymExpr *LHS;
@@ -408,6 +444,9 @@ public:
                                           QualType T, unsigned VisitCount,
                                           const void *SymbolTag = 0);
 
+  const SymbolCast* getCastSymbol(const SymExpr *Operand,
+                                  QualType From, QualType To);
+
   const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
                                   const llvm::APSInt& rhs, QualType t);
 
index 79f4348b7c1322fd5e9fb5d77f9865d9c4e740e4..2dafeeee00faba9a9061ffbe92e0e5fc6a664071 100644 (file)
@@ -560,6 +560,8 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
     case SymExpr::ExtentKind:
     case SymExpr::MetadataKind:
       break;
+    case SymExpr::CastSymbolKind:
+      return scan(cast<SymbolCast>(sym)->getOperand());
     case SymExpr::SymIntKind:
       return scan(cast<SymIntExpr>(sym)->getLHS());
     case SymExpr::SymSymKind: {
@@ -672,10 +674,15 @@ bool ProgramState::isTainted(const SymExpr* Sym, TaintTagType Kind) const {
   if (!Sym)
     return false;
 
+  // TODO: Can we use symbol_iterator (like removeDeadBindingsWorker) here?
+
   // Check taint on derived symbols.
   if (const SymbolDerived *SD = dyn_cast<SymbolDerived>(Sym))
     return isTainted(SD->getParentSymbol(), Kind);
 
+  if (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+    return (isTainted(SC->getOperand(), Kind));
+
   if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(Sym))
     return isTainted(SIE->getLHS(), Kind);
 
index 27077afadaba1dab80187b97002bfee210a86c57..4f811dfa733a705de5ac9b551912ee49e275905e 100644 (file)
@@ -1720,7 +1720,7 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
   if (const MemRegion *R = V.getAsRegion())
     AddToWorkList(R);
 
-    // Update the set of live symbols.
+  // Update the set of live symbols.
   for (SVal::symbol_iterator SI=V.symbol_begin(), SE=V.symbol_end();
        SI!=SE;++SI)
     SymReaper.markLive(*SI);
index 617e0ddc729b88aeb70b06f454461e1bce1e8ee4..ff0a85a5723c4b166fb8717e72121de6f2dfed2e 100644 (file)
@@ -56,6 +56,12 @@ NonLoc SValBuilder::makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
   return nonloc::SymbolVal(SymMgr.getSymSymExpr(lhs, op, rhs, type));
 }
 
+NonLoc SValBuilder::makeNonLoc(const SymExpr *operand,
+                               QualType fromTy, QualType toTy) {
+  assert(operand);
+  assert(!Loc::isLocType(toTy));
+  return nonloc::SymbolVal(SymMgr.getCastSymbol(operand, fromTy, toTy));
+}
 
 SVal SValBuilder::convertToArrayIndex(SVal val) {
   if (val.isUnknownOrUndef())
@@ -220,21 +226,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
   if (!castTy->isVariableArrayType() && !originalTy->isVariableArrayType())
     if (Context.hasSameUnqualifiedType(castTy, originalTy))
       return val;
-
-  // Check for casts to real or complex numbers.  We don't handle these at all
-  // right now.
-  if (castTy->isFloatingType() || castTy->isAnyComplexType())
-    return UnknownVal();
   
-  // Check for casts from integers to integers.
-  if (castTy->isIntegerType() && originalTy->isIntegerType()) {
-    if (isa<Loc>(val))
-      // This can be a cast to ObjC property of type int.
-      return evalCastFromLoc(cast<Loc>(val), castTy);
-    else
-      return evalCastFromNonLoc(cast<NonLoc>(val), castTy);
-  }
-
   // Check for casts from pointers to integers.
   if (castTy->isIntegerType() && Loc::isLocType(originalTy))
     return evalCastFromLoc(cast<Loc>(val), castTy);
@@ -249,7 +241,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
       }
       return LV->getLoc();
     }
-    goto DispatchCast;
+    return dispatchCast(val, castTy);
   }
 
   // Just pass through function and block pointers.
@@ -323,8 +315,9 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
     return R ? SVal(loc::MemRegionVal(R)) : UnknownVal();
   }
 
-DispatchCast:
-  // All other cases.
-  return isa<Loc>(val) ? evalCastFromLoc(cast<Loc>(val), castTy)
-                       : evalCastFromNonLoc(cast<NonLoc>(val), castTy);
+  // Check for casts from integers to integers.
+  if (castTy->isIntegerType() && originalTy->isIntegerType())
+    return dispatchCast(val, castTy);
+
+  return dispatchCast(val, castTy);
 }
index 4bdea1d9e1d146388b89a2b624e8ebce1c032ae5..97e5a1be4c6634c438b01f4a5c30481b40b3cbb7 100644 (file)
@@ -91,6 +91,7 @@ SymbolRef SVal::getLocSymbolInBase() const {
   return 0;
 }
 
+// TODO: The next 3 functions have to be simplified.
 /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
 ///  Otherwise return 0.
 // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
@@ -168,6 +169,10 @@ void SVal::symbol_iterator::expand() {
   const SymExpr *SE = itr.back();
   itr.pop_back();
 
+  if (const SymbolCast *SC = dyn_cast<SymbolCast>(SE)) {
+    itr.push_back(SC->getOperand());
+    return;
+  }
   if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SE)) {
     itr.push_back(SIE->getLHS());
     return;
index 495f6f20b674b4d6aea386f22a85cf2f530d671f..da07d8ad0f6c13cebe6574e3fb68e8e3debea7d2 100644 (file)
@@ -20,6 +20,7 @@ using namespace ento;
 namespace {
 class SimpleSValBuilder : public SValBuilder {
 protected:
+  virtual SVal dispatchCast(SVal val, QualType castTy);
   virtual SVal evalCastFromNonLoc(NonLoc val, QualType castTy);
   virtual SVal evalCastFromLoc(Loc val, QualType castTy);
 
@@ -57,6 +58,11 @@ SValBuilder *ento::createSimpleSValBuilder(llvm::BumpPtrAllocator &alloc,
 // Transfer function for Casts.
 //===----------------------------------------------------------------------===//
 
+SVal SimpleSValBuilder::dispatchCast(SVal val, QualType castTy) {
+  return isa<Loc>(val) ? evalCastFromLoc(cast<Loc>(val), castTy)
+                       : evalCastFromNonLoc(cast<NonLoc>(val), castTy);
+}
+
 SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
 
   bool isLocType = Loc::isLocType(castTy);
@@ -86,6 +92,8 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) {
     if (T->isIntegerType() && castTy->isIntegerType())
       return val;
 
+    if (!isLocType)
+      return makeNonLoc(se, T, castTy);
     return UnknownVal();
   }
 
index 48a6f4f60f8a14e581c21d9f21a4c11540e44d47..5d152d4d53366199ad7f0185b1e5ed6f84de1378 100644 (file)
@@ -212,7 +212,7 @@ const MemRegion *StoreManager::castRegion(const MemRegion *R, QualType CastToTy)
 SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
                                     QualType castTy, bool performTestOnly) {
   
-  if (castTy.isNull())
+  if (castTy.isNull() || V.isUnknownOrUndef())
     return V;
   
   ASTContext &Ctx = svalBuilder.getContext();
@@ -227,12 +227,8 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
     return V;
   }
   
-  if (const Loc *L = dyn_cast<Loc>(&V))
-    return svalBuilder.evalCastFromLoc(*L, castTy);
-  else if (const NonLoc *NL = dyn_cast<NonLoc>(&V))
-    return svalBuilder.evalCastFromNonLoc(*NL, castTy);
-  
-  return V;
+  assert(isa<Loc>(&V) || isa<NonLoc>(&V));
+  return svalBuilder.dispatchCast(V, castTy);
 }
 
 SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
index b843ab1a903b7440c96d87903e7ce58b8431fdef..02c0a9e36d400f06b80889d25ef93778a996d57f 100644 (file)
@@ -66,6 +66,12 @@ void SymSymExpr::dumpToStream(raw_ostream &os) const {
   os << ')';
 }
 
+void SymbolCast::dumpToStream(raw_ostream &os) const {
+  os << '(' << ToTy.getAsString() << ") (";
+  Operand->dumpToStream(os);
+  os << ')';
+}
+
 void SymbolConjured::dumpToStream(raw_ostream &os) const {
   os << "conj_$" << getSymbolID() << '{' << T.getAsString() << '}';
 }
@@ -174,6 +180,22 @@ SymbolManager::getMetadataSymbol(const MemRegion* R, const Stmt *S, QualType T,
   return cast<SymbolMetadata>(SD);
 }
 
+const SymbolCast*
+SymbolManager::getCastSymbol(const SymExpr *Op,
+                             QualType From, QualType To) {
+  llvm::FoldingSetNodeID ID;
+  SymbolCast::Profile(ID, Op, From, To);
+  void *InsertPos;
+  SymExpr *data = DataSet.FindNodeOrInsertPos(ID, InsertPos);
+  if (!data) {
+    data = (SymbolCast*) BPAlloc.Allocate<SymbolCast>();
+    new (data) SymbolCast(Op, From, To);
+    DataSet.InsertNode(data, InsertPos);
+  }
+
+  return cast<SymbolCast>(data);
+}
+
 const SymIntExpr *SymbolManager::getSymIntExpr(const SymExpr *lhs,
                                                BinaryOperator::Opcode op,
                                                const llvm::APSInt& v,
index b424d5d5b047536404315d27a4be178f672d7405..eb05f577d1b74739e1e4aad4dfca5c0091cdf31d 100644 (file)
@@ -12,4 +12,12 @@ void bufferScanfAssignment(int x) {
   scanf("%d", &n);
   addr += n;// expected-warning {{tainted}}
   *addr = n; // expected-warning 2 {{tainted}}
+
+  double tdiv = n / 30; // expected-warning 3 {{tainted}}
+  char *loc_cast = (char *) n; // expected-warning {{tainted}}
+  char tinc = tdiv++; // expected-warning {{tainted}}
+  int tincdec = (char)tinc--; // expected-warning 2 {{tainted}}
+  int tprtarithmetic1 = *(addr+1);
+
+
 }