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(SymbolID((uintptr_t)Data));
Zhongxing Xu
committed
else if (isa<nonloc::SymbolVal>(this))
Ted Kremenek
committed
return symbol_iterator(SymbolID((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
//===----------------------------------------------------------------------===//
// 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.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
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.
//===----------------------------------------------------------------------===//
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())));
Zhongxing Xu
committed
NonLoc NonLoc::MakeIntTruthVal(BasicValueFactory& BasicVals, bool b) {
return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
}
Zhongxing Xu
committed
NonLoc NonLoc::MakeCompoundVal(QualType T, SVal* Vals, unsigned NumSVals,
BasicValueFactory& BasicVals) {
return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals, NumSVals));
}
Zhongxing Xu
committed
SVal SVal::GetSymbolValue(SymbolManager& SymMgr, VarDecl* D) {
QualType T = D->getType();
Zhongxing Xu
committed
if (Loc::IsLocType(T))
return loc::SymbolVal(SymMgr.getSymbol(D));
Zhongxing Xu
committed
return nonloc::SymbolVal(SymMgr.getSymbol(D));
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
// Utility methods for constructing Locs.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
Loc Loc::MakeVal(AddrLabelExpr* E) { return loc::GotoLabel(E->getLabel()); }
//===----------------------------------------------------------------------===//
// Pretty-Printing.
//===----------------------------------------------------------------------===//
Zhongxing Xu
committed
void SVal::printStdErr() const { print(*llvm::cerr.stream()); }
Zhongxing Xu
committed
void SVal::print(std::ostream& Out) const {
switch (getBaseKind()) {
Out << "Invalid"; break;
Zhongxing Xu
committed
case NonLocKind:
cast<NonLoc>(this)->print(Out); break;
Zhongxing Xu
committed
case LocKind:
cast<Loc>(this)->print(Out); break;
Ted Kremenek
committed
case UndefinedKind:
Out << "Undefined"; break;
Zhongxing Xu
committed
assert (false && "Invalid SVal.");
static void printOpcode(std::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.");
}
}
Zhongxing Xu
committed
void NonLoc::print(std::ostream& Out) const {
switch (getSubKind()) {
Zhongxing Xu
committed
case nonloc::ConcreteIntKind:
Out << cast<nonloc::ConcreteInt>(this)->getValue().getZExtValue();
Zhongxing Xu
committed
if (cast<nonloc::ConcreteInt>(this)->getValue().isUnsigned())
Out << 'U';
Zhongxing Xu
committed
case nonloc::SymbolValKind:
Out << '$' << cast<nonloc::SymbolVal>(this)->getSymbol();
Zhongxing Xu
committed
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';
Ted Kremenek
committed
}
Zhongxing Xu
committed
case nonloc::LocAsIntegerKind: {
const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
C.getLoc().print(Out);
Ted Kremenek
committed
Out << " [as " << C.getNumBits() << " bit integer]";
break;
}
Zhongxing Xu
committed
assert (false && "Pretty-printed not implemented for this NonLoc.");
break;
}
}
Zhongxing Xu
committed
void Loc::print(std::ostream& Out) const {
switch (getSubKind()) {
Zhongxing Xu
committed
case loc::ConcreteIntKind:
Out << cast<loc::ConcreteInt>(this)->getValue().getZExtValue()
<< " (Loc)";
Zhongxing Xu
committed
case loc::SymbolValKind:
Out << '$' << cast<loc::SymbolVal>(this)->getSymbol();
Zhongxing Xu
committed
case loc::GotoLabelKind:
Out << "&&"
Zhongxing Xu
committed
<< cast<loc::GotoLabel>(this)->getLabel()->getID()->getName();
break;
Ted Kremenek
committed
Zhongxing Xu
committed
case loc::MemRegionKind:
Out << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
Zhongxing Xu
committed
case loc::FuncValKind:
Out << "function "
Zhongxing Xu
committed
<< cast<loc::FuncVal>(this)->getDecl()->getIdentifier()->getName();
break;
default:
Zhongxing Xu
committed
assert (false && "Pretty-printing not implemented for this Loc.");
break;
}
}
395
396
397
398
399
400
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
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
//===----------------------------------------------------------------------===//
// Pretty-Printing with llvm::raw_ostream.
//===----------------------------------------------------------------------===//
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;
}
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;
}
}