Newer
Older
//= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
Zhongxing Xu
committed
// This file defines SVal, Loc, and NonLoc, classes that represent
// abstract r-values for use with path-sensitive value tracking.
//
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/Support/Streams.h"
using namespace clang;
using llvm::dyn_cast;
using llvm::cast;
using llvm::APSInt;
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Symbol Iteration.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
SVal::symbol_iterator SVal::symbol_begin() const {
Ted Kremenek
committed
// FIXME: This is a rat's nest. Cleanup.
Zhongxing Xu
committed
if (isa<loc::SymbolVal>(this))
Ted Kremenek
committed
return symbol_iterator(SymbolRef((uintptr_t)Data));
Zhongxing Xu
committed
else if (isa<nonloc::SymbolVal>(this))
Ted Kremenek
committed
return symbol_iterator(SymbolRef((uintptr_t)Data));
Zhongxing Xu
committed
else if (isa<nonloc::SymIntConstraintVal>(this)) {
const SymIntConstraint& C =
Ted Kremenek
committed
cast<nonloc::SymIntConstraintVal>(this)->getConstraint();
return symbol_iterator(C.getSymbol());
Ted Kremenek
committed
}
Zhongxing Xu
committed
else if (isa<nonloc::LocAsInteger>(this)) {
const nonloc::LocAsInteger& V = cast<nonloc::LocAsInteger>(*this);
return V.getPersistentLoc().symbol_begin();
Ted Kremenek
committed
}
Ted Kremenek
committed
else if (isa<loc::MemRegionVal>(this)) {
const MemRegion* R = cast<loc::MemRegionVal>(this)->getRegion();
if (const SymbolicRegion* S = dyn_cast<SymbolicRegion>(R))
return symbol_iterator(S->getSymbol());
}
Ted Kremenek
committed
Ted Kremenek
committed
return symbol_iterator();
Ted Kremenek
committed
}
Zhongxing Xu
committed
SVal::symbol_iterator SVal::symbol_end() const {
Ted Kremenek
committed
return symbol_iterator();
Ted Kremenek
committed
}
Ted Kremenek
committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
/// wraps a symbol, return that SymbolRef. Otherwise return a SymbolRef
/// where 'isValid()' returns false.
SymbolRef SVal::getAsLocSymbol() const {
if (const loc::SymbolVal *X = dyn_cast<loc::SymbolVal>(this))
return X->getSymbol();
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
const MemRegion *R = X->getRegion();
while (R) {
// Blast through region views.
if (const TypedViewRegion *View = dyn_cast<TypedViewRegion>(R)) {
R = View->getSuperRegion();
continue;
}
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
return SymR->getSymbol();
break;
}
}
return SymbolRef();
}
/// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
/// Otherwise return a SymbolRef where 'isValid()' returns false.
SymbolRef SVal::getAsSymbol() const {
if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
return X->getSymbol();
return getAsLocSymbol();
}
//===----------------------------------------------------------------------===//
// Other Iterators.
//===----------------------------------------------------------------------===//
nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
return getValue()->begin();
}
nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
return getValue()->end();
}
Ted Kremenek
committed
//===----------------------------------------------------------------------===//
// Useful predicates.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
bool SVal::isZeroConstant() const {
if (isa<loc::ConcreteInt>(*this))
return cast<loc::ConcreteInt>(*this).getValue() == 0;
else if (isa<nonloc::ConcreteInt>(*this))
return cast<nonloc::ConcreteInt>(*this).getValue() == 0;
Ted Kremenek
committed
else
return false;
}
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
// Transfer function dispatch for Non-Locs.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
SVal nonloc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
Zhongxing Xu
committed
const nonloc::ConcreteInt& R) const {
const llvm::APSInt* X =
BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
Ted Kremenek
committed
if (X)
Zhongxing Xu
committed
return nonloc::ConcreteInt(*X);
Ted Kremenek
committed
else
return UndefinedVal();
}
// Bitwise-Complement.
Zhongxing Xu
committed
nonloc::ConcreteInt
nonloc::ConcreteInt::EvalComplement(BasicValueFactory& BasicVals) const {
return BasicVals.getValue(~getValue());
}
// Unary Minus.
Zhongxing Xu
committed
nonloc::ConcreteInt
nonloc::ConcreteInt::EvalMinus(BasicValueFactory& BasicVals, UnaryOperator* U) const {
assert (U->getType() == U->getSubExpr()->getType());
assert (U->getType()->isIntegerType());
return BasicVals.getValue(-getValue());
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
// Transfer function dispatch for Locs.
//===----------------------------------------------------------------------===//
SVal loc::ConcreteInt::EvalBinOp(BasicValueFactory& BasicVals,
BinaryOperator::Opcode Op,
const loc::ConcreteInt& R) const {
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub ||
(Op >= BinaryOperator::LT && Op <= BinaryOperator::NE));
const llvm::APSInt* X = BasicVals.EvaluateAPSInt(Op, getValue(), R.getValue());
Ted Kremenek
committed
if (X)
Zhongxing Xu
committed
return loc::ConcreteInt(*X);
Ted Kremenek
committed
else
return UndefinedVal();
Zhongxing Xu
committed
NonLoc Loc::EQ(BasicValueFactory& BasicVals, const Loc& R) const {
switch (getSubKind()) {
default:
Zhongxing Xu
committed
assert(false && "EQ not implemented for this Loc.");
break;
Zhongxing Xu
committed
case loc::ConcreteIntKind:
if (isa<loc::ConcreteInt>(R)) {
bool b = cast<loc::ConcreteInt>(this)->getValue() ==
cast<loc::ConcreteInt>(R).getValue();
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, b);
Zhongxing Xu
committed
else if (isa<loc::SymbolVal>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(R).getSymbol(),
BinaryOperator::EQ,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(this)->getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
}
break;
Zhongxing Xu
committed
case loc::SymbolValKind: {
if (isa<loc::ConcreteInt>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(this)->getSymbol(),
BinaryOperator::EQ,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(R).getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
}
Zhongxing Xu
committed
assert (!isa<loc::SymbolVal>(R) && "FIXME: Implement unification.");
break;
Zhongxing Xu
committed
case loc::MemRegionKind:
if (isa<loc::MemRegionVal>(R)) {
bool b = cast<loc::MemRegionVal>(*this) == cast<loc::MemRegionVal>(R);
return NonLoc::MakeIntTruthVal(BasicVals, b);
}
break;
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, false);
Zhongxing Xu
committed
NonLoc Loc::NE(BasicValueFactory& BasicVals, const Loc& R) const {
switch (getSubKind()) {
default:
Zhongxing Xu
committed
assert(false && "NE not implemented for this Loc.");
break;
Zhongxing Xu
committed
case loc::ConcreteIntKind:
if (isa<loc::ConcreteInt>(R)) {
bool b = cast<loc::ConcreteInt>(this)->getValue() !=
cast<loc::ConcreteInt>(R).getValue();
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, b);
Zhongxing Xu
committed
else if (isa<loc::SymbolVal>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(R).getSymbol(),
BinaryOperator::NE,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(this)->getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
Zhongxing Xu
committed
case loc::SymbolValKind: {
if (isa<loc::ConcreteInt>(R)) {
const SymIntConstraint& C =
Zhongxing Xu
committed
BasicVals.getConstraint(cast<loc::SymbolVal>(this)->getSymbol(),
BinaryOperator::NE,
Zhongxing Xu
committed
cast<loc::ConcreteInt>(R).getValue());
Zhongxing Xu
committed
return nonloc::SymIntConstraintVal(C);
Zhongxing Xu
committed
assert (!isa<loc::SymbolVal>(R) && "FIXME: Implement sym !=.");
break;
}
Zhongxing Xu
committed
case loc::MemRegionKind:
if (isa<loc::MemRegionVal>(R)) {
bool b = cast<loc::MemRegionVal>(*this)==cast<loc::MemRegionVal>(R);
return NonLoc::MakeIntTruthVal(BasicVals, b);
}
break;
Zhongxing Xu
committed
return NonLoc::MakeIntTruthVal(BasicVals, true);
}
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
// Utility methods for constructing Non-Locs.
//===----------------------------------------------------------------------===//
NonLoc NonLoc::MakeVal(SymbolRef sym) {
return nonloc::SymbolVal(sym);
Zhongxing Xu
committed
}
NonLoc NonLoc::MakeVal(SymbolManager& SymMgr, SymbolRef lhs,
BinaryOperator::Opcode op, const APSInt& v) {
// The Environment ensures we always get a persistent APSInt in
// BasicValueFactory, so we don't need to get the APSInt from
// BasicValueFactory again.
SymbolRef sym = SymMgr.getSymIntExpr(lhs, op, v, SymMgr.getType(lhs));
return nonloc::SymbolVal(sym);
}
NonLoc NonLoc::MakeVal(SymbolManager& SymMgr, SymbolRef lhs,
BinaryOperator::Opcode op, SymbolRef rhs) {
assert(SymMgr.getType(lhs) == SymMgr.getType(rhs));
SymbolRef sym = SymMgr.getSymSymExpr(lhs, op, rhs, SymMgr.getType(lhs));
return nonloc::SymbolVal(sym);
NonLoc NonLoc::MakeIntVal(BasicValueFactory& BasicVals, uint64_t X,
bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X,
unsigned BitWidth, bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
}
Zhongxing Xu
committed
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, uint64_t X, QualType T) {
return nonloc::ConcreteInt(BasicVals.getValue(X, T));
Zhongxing Xu
committed
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, IntegerLiteral* I) {
Zhongxing Xu
committed
return nonloc::ConcreteInt(BasicVals.getValue(APSInt(I->getValue(),
I->getType()->isUnsignedIntegerType())));
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APInt& I,
bool isUnsigned) {
return nonloc::ConcreteInt(BasicVals.getValue(I, isUnsigned));
}
NonLoc NonLoc::MakeVal(BasicValueFactory& BasicVals, const llvm::APSInt& I) {
return nonloc::ConcreteInt(BasicVals.getValue(I));
}
Zhongxing Xu
committed
NonLoc NonLoc::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
}
Ted Kremenek
committed
NonLoc NonLoc::MakeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals,
Zhongxing Xu
committed
BasicValueFactory& BasicVals) {
Ted Kremenek
committed
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
Zhongxing Xu
committed
}
SVal SVal::GetRValueSymbolVal(SymbolManager& SymMgr, const MemRegion* R) {
SymbolRef sym = SymMgr.getRegionRValueSymbol(R);
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R)) {
QualType T = TR->getRValueType(SymMgr.getContext());
if (Loc::IsLocType(T))
return Loc::MakeVal(sym);
// Only handle integers for now.
if (T->isIntegerType())
return NonLoc::MakeVal(sym);
}
return UnknownVal();
SVal SVal::GetConjuredSymbolVal(SymbolManager &SymMgr, const Expr* E,
unsigned Count) {
QualType T = E->getType();
if (Loc::IsLocType(T)) {
SymbolRef Sym = SymMgr.getConjuredSymbol(E, Count);
return loc::SymbolVal(Sym);
}
else if (T->isIntegerType() && T->isScalarType()) {
SymbolRef Sym = SymMgr.getConjuredSymbol(E, Count);
return nonloc::SymbolVal(Sym);
}
return UnknownVal();
}
Ted Kremenek
committed
nonloc::LocAsInteger nonloc::LocAsInteger::Make(BasicValueFactory& Vals, Loc V,
unsigned Bits) {
return LocAsInteger(Vals.getPersistentSValWithData(V, Bits));
}
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
// Utility methods for constructing Locs.
//===----------------------------------------------------------------------===//
Loc Loc::MakeVal(const MemRegion* R) { return loc::MemRegionVal(R); }
Zhongxing Xu
committed
Loc Loc::MakeVal(AddrLabelExpr* E) { return loc::GotoLabel(E->getLabel()); }
Loc Loc::MakeVal(SymbolRef sym) { return loc::SymbolVal(sym); }
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//
void SVal::printStdErr() const { print(llvm::errs()); }
Zhongxing Xu
committed
void SVal::print(std::ostream& Out) const {
llvm::raw_os_ostream out(Out);
print(out);
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
void SVal::print(llvm::raw_ostream& Out) const {
switch (getBaseKind()) {
case UnknownKind:
Out << "Invalid"; break;
case NonLocKind:
cast<NonLoc>(this)->print(Out); break;
case LocKind:
cast<Loc>(this)->print(Out); break;
case UndefinedKind:
Out << "Undefined"; break;
default:
assert (false && "Invalid SVal.");
}
}
static void printOpcode(llvm::raw_ostream& Out, BinaryOperator::Opcode Op) {
switch (Op) {
case BinaryOperator::Mul: Out << '*' ; break;
case BinaryOperator::Div: Out << '/' ; break;
case BinaryOperator::Rem: Out << '%' ; break;
case BinaryOperator::Add: Out << '+' ; break;
case BinaryOperator::Sub: Out << '-' ; break;
case BinaryOperator::Shl: Out << "<<" ; break;
case BinaryOperator::Shr: Out << ">>" ; break;
case BinaryOperator::LT: Out << "<" ; break;
case BinaryOperator::GT: Out << '>' ; break;
case BinaryOperator::LE: Out << "<=" ; break;
case BinaryOperator::GE: Out << ">=" ; break;
case BinaryOperator::EQ: Out << "==" ; break;
case BinaryOperator::NE: Out << "!=" ; break;
case BinaryOperator::And: Out << '&' ; break;
case BinaryOperator::Xor: Out << '^' ; break;
case BinaryOperator::Or: Out << '|' ; break;
default: assert(false && "Not yet implemented.");
}
}
void NonLoc::print(llvm::raw_ostream& Out) const {
switch (getSubKind()) {
case nonloc::ConcreteIntKind:
Out << cast<nonloc::ConcreteInt>(this)->getValue().getZExtValue();
if (cast<nonloc::ConcreteInt>(this)->getValue().isUnsigned())
Out << 'U';
break;
case nonloc::SymbolValKind:
Out << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
break;
case nonloc::SymIntConstraintValKind: {
const nonloc::SymIntConstraintVal& C =
*cast<nonloc::SymIntConstraintVal>(this);
Out << '$' << C.getConstraint().getSymbol() << ' ';
printOpcode(Out, C.getConstraint().getOpcode());
Out << ' ' << C.getConstraint().getInt().getZExtValue();
if (C.getConstraint().getInt().isUnsigned())
Out << 'U';
break;
}
case nonloc::LocAsIntegerKind: {
const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
C.getLoc().print(Out);
Out << " [as " << C.getNumBits() << " bit integer]";
break;
}
case nonloc::CompoundValKind: {
const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
Out << " {";
bool first = true;
for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
if (first) { Out << ' '; first = false; }
else Out << ", ";
}
Out << " }";
break;
}
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
default:
assert (false && "Pretty-printed not implemented for this NonLoc.");
break;
}
}
void Loc::print(llvm::raw_ostream& Out) const {
switch (getSubKind()) {
case loc::ConcreteIntKind:
Out << cast<loc::ConcreteInt>(this)->getValue().getZExtValue()
<< " (Loc)";
break;
case loc::SymbolValKind:
Out << '$' << cast<loc::SymbolVal>(this)->getSymbol();
break;
case loc::GotoLabelKind:
Out << "&&"
<< cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
break;
case loc::MemRegionKind:
Out << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
break;
case loc::FuncValKind:
Out << "function "
<< cast<loc::FuncVal>(this)->getDecl()->getIdentifier()->getName();
break;
default:
assert (false && "Pretty-printing not implemented for this Loc.");
break;
}
}