[analyzer] Propagate taint through NonLoc to NonLoc casts.

- 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.

llvm-svn: 145985
This commit is contained in:
Anna Zaks 2011-12-06 23:12:27 +00:00
parent 8629c0a4d0
commit c25efccc8b
11 changed files with 114 additions and 30 deletions

View 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));
}

View 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) {}

View 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);

View 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);

View 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);

View 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())
@ -221,20 +227,6 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
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);
}

View 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;

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

View 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) {

View 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,

View 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);
}