forked from OSchip/llvm-project
[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:
parent
8629c0a4d0
commit
c25efccc8b
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -299,6 +299,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief Value representing integer constant.
|
||||
class ConcreteInt : public NonLoc {
|
||||
public:
|
||||
explicit ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue