Home | History | Annotate | Download | only in Core
      1 //= RValues.cpp - Abstract RValues for Path-Sens. Value Tracking -*- C++ -*-==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 //  This file defines SVal, Loc, and NonLoc, classes that represent
     11 //  abstract r-values for use with path-sensitive value tracking.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
     16 #include "clang/AST/ExprObjC.h"
     17 #include "clang/Basic/IdentifierTable.h"
     18 using namespace clang;
     19 using namespace ento;
     20 using llvm::APSInt;
     21 
     22 //===----------------------------------------------------------------------===//
     23 // Symbol iteration within an SVal.
     24 //===----------------------------------------------------------------------===//
     25 
     26 
     27 //===----------------------------------------------------------------------===//
     28 // Utility methods.
     29 //===----------------------------------------------------------------------===//
     30 
     31 bool SVal::hasConjuredSymbol() const {
     32   if (const nonloc::SymbolVal* SV = dyn_cast<nonloc::SymbolVal>(this)) {
     33     SymbolRef sym = SV->getSymbol();
     34     if (isa<SymbolConjured>(sym))
     35       return true;
     36   }
     37 
     38   if (const loc::MemRegionVal *RV = dyn_cast<loc::MemRegionVal>(this)) {
     39     const MemRegion *R = RV->getRegion();
     40     if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
     41       SymbolRef sym = SR->getSymbol();
     42       if (isa<SymbolConjured>(sym))
     43         return true;
     44     }
     45   }
     46 
     47   return false;
     48 }
     49 
     50 const FunctionDecl *SVal::getAsFunctionDecl() const {
     51   if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) {
     52     const MemRegion* R = X->getRegion();
     53     if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>())
     54       return CTR->getDecl();
     55   }
     56 
     57   return 0;
     58 }
     59 
     60 /// \brief If this SVal is a location (subclasses Loc) and wraps a symbol,
     61 /// return that SymbolRef.  Otherwise return 0.
     62 ///
     63 /// Implicit casts (ex: void* -> char*) can turn Symbolic region into Element
     64 /// region. If that is the case, gets the underlining region.
     65 SymbolRef SVal::getAsLocSymbol() const {
     66   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
     67   if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this))
     68     return X->getLoc().getAsLocSymbol();
     69 
     70   if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this)) {
     71     const MemRegion *R = X->stripCasts();
     72     if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R))
     73       return SymR->getSymbol();
     74   }
     75   return 0;
     76 }
     77 
     78 /// Get the symbol in the SVal or its base region.
     79 SymbolRef SVal::getLocSymbolInBase() const {
     80   const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this);
     81 
     82   if (!X)
     83     return 0;
     84 
     85   const MemRegion *R = X->getRegion();
     86 
     87   while (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
     88     if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(SR))
     89       return SymR->getSymbol();
     90     else
     91       R = SR->getSuperRegion();
     92   }
     93 
     94   return 0;
     95 }
     96 
     97 // TODO: The next 3 functions have to be simplified.
     98 
     99 /// \brief If this SVal wraps a symbol return that SymbolRef.
    100 ///  Otherwise return 0.
    101 SymbolRef SVal::getAsSymbol() const {
    102   // FIXME: should we consider SymbolRef wrapped in CodeTextRegion?
    103   if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    104     return X->getSymbol();
    105 
    106   return getAsLocSymbol();
    107 }
    108 
    109 /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
    110 ///  return that expression.  Otherwise return NULL.
    111 const SymExpr *SVal::getAsSymbolicExpression() const {
    112   if (const nonloc::SymbolVal *X = dyn_cast<nonloc::SymbolVal>(this))
    113     return X->getSymbol();
    114 
    115   return getAsSymbol();
    116 }
    117 
    118 const SymExpr* SVal::getAsSymExpr() const {
    119   const SymExpr* Sym = getAsSymbol();
    120   if (!Sym)
    121     Sym = getAsSymbolicExpression();
    122   return Sym;
    123 }
    124 
    125 const MemRegion *SVal::getAsRegion() const {
    126   if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(this))
    127     return X->getRegion();
    128 
    129   if (const nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(this)) {
    130     return X->getLoc().getAsRegion();
    131   }
    132 
    133   return 0;
    134 }
    135 
    136 const MemRegion *loc::MemRegionVal::stripCasts() const {
    137   const MemRegion *R = getRegion();
    138   return R ?  R->StripCasts() : NULL;
    139 }
    140 
    141 const void *nonloc::LazyCompoundVal::getStore() const {
    142   return static_cast<const LazyCompoundValData*>(Data)->getStore();
    143 }
    144 
    145 const TypedRegion *nonloc::LazyCompoundVal::getRegion() const {
    146   return static_cast<const LazyCompoundValData*>(Data)->getRegion();
    147 }
    148 
    149 //===----------------------------------------------------------------------===//
    150 // Other Iterators.
    151 //===----------------------------------------------------------------------===//
    152 
    153 nonloc::CompoundVal::iterator nonloc::CompoundVal::begin() const {
    154   return getValue()->begin();
    155 }
    156 
    157 nonloc::CompoundVal::iterator nonloc::CompoundVal::end() const {
    158   return getValue()->end();
    159 }
    160 
    161 //===----------------------------------------------------------------------===//
    162 // Useful predicates.
    163 //===----------------------------------------------------------------------===//
    164 
    165 bool SVal::isConstant() const {
    166   return isa<nonloc::ConcreteInt>(this) || isa<loc::ConcreteInt>(this);
    167 }
    168 
    169 bool SVal::isConstant(int I) const {
    170   if (isa<loc::ConcreteInt>(*this))
    171     return cast<loc::ConcreteInt>(*this).getValue() == I;
    172   else if (isa<nonloc::ConcreteInt>(*this))
    173     return cast<nonloc::ConcreteInt>(*this).getValue() == I;
    174   else
    175     return false;
    176 }
    177 
    178 bool SVal::isZeroConstant() const {
    179   return isConstant(0);
    180 }
    181 
    182 
    183 //===----------------------------------------------------------------------===//
    184 // Transfer function dispatch for Non-Locs.
    185 //===----------------------------------------------------------------------===//
    186 
    187 SVal nonloc::ConcreteInt::evalBinOp(SValBuilder &svalBuilder,
    188                                     BinaryOperator::Opcode Op,
    189                                     const nonloc::ConcreteInt& R) const {
    190   const llvm::APSInt* X =
    191     svalBuilder.getBasicValueFactory().evalAPSInt(Op, getValue(), R.getValue());
    192 
    193   if (X)
    194     return nonloc::ConcreteInt(*X);
    195   else
    196     return UndefinedVal();
    197 }
    198 
    199 nonloc::ConcreteInt
    200 nonloc::ConcreteInt::evalComplement(SValBuilder &svalBuilder) const {
    201   return svalBuilder.makeIntVal(~getValue());
    202 }
    203 
    204 nonloc::ConcreteInt
    205 nonloc::ConcreteInt::evalMinus(SValBuilder &svalBuilder) const {
    206   return svalBuilder.makeIntVal(-getValue());
    207 }
    208 
    209 //===----------------------------------------------------------------------===//
    210 // Transfer function dispatch for Locs.
    211 //===----------------------------------------------------------------------===//
    212 
    213 SVal loc::ConcreteInt::evalBinOp(BasicValueFactory& BasicVals,
    214                                  BinaryOperator::Opcode Op,
    215                                  const loc::ConcreteInt& R) const {
    216 
    217   assert (Op == BO_Add || Op == BO_Sub ||
    218           (Op >= BO_LT && Op <= BO_NE));
    219 
    220   const llvm::APSInt* X = BasicVals.evalAPSInt(Op, getValue(), R.getValue());
    221 
    222   if (X)
    223     return loc::ConcreteInt(*X);
    224   else
    225     return UndefinedVal();
    226 }
    227 
    228 //===----------------------------------------------------------------------===//
    229 // Pretty-Printing.
    230 //===----------------------------------------------------------------------===//
    231 
    232 void SVal::dump() const { dumpToStream(llvm::errs()); }
    233 
    234 void SVal::dumpToStream(raw_ostream &os) const {
    235   switch (getBaseKind()) {
    236     case UnknownKind:
    237       os << "Unknown";
    238       break;
    239     case NonLocKind:
    240       cast<NonLoc>(this)->dumpToStream(os);
    241       break;
    242     case LocKind:
    243       cast<Loc>(this)->dumpToStream(os);
    244       break;
    245     case UndefinedKind:
    246       os << "Undefined";
    247       break;
    248   }
    249 }
    250 
    251 void NonLoc::dumpToStream(raw_ostream &os) const {
    252   switch (getSubKind()) {
    253     case nonloc::ConcreteIntKind: {
    254       const nonloc::ConcreteInt& C = *cast<nonloc::ConcreteInt>(this);
    255       if (C.getValue().isUnsigned())
    256         os << C.getValue().getZExtValue();
    257       else
    258         os << C.getValue().getSExtValue();
    259       os << ' ' << (C.getValue().isUnsigned() ? 'U' : 'S')
    260          << C.getValue().getBitWidth() << 'b';
    261       break;
    262     }
    263     case nonloc::SymbolValKind: {
    264       os << cast<nonloc::SymbolVal>(this)->getSymbol();
    265       break;
    266     }
    267     case nonloc::LocAsIntegerKind: {
    268       const nonloc::LocAsInteger& C = *cast<nonloc::LocAsInteger>(this);
    269       os << C.getLoc() << " [as " << C.getNumBits() << " bit integer]";
    270       break;
    271     }
    272     case nonloc::CompoundValKind: {
    273       const nonloc::CompoundVal& C = *cast<nonloc::CompoundVal>(this);
    274       os << "compoundVal{";
    275       bool first = true;
    276       for (nonloc::CompoundVal::iterator I=C.begin(), E=C.end(); I!=E; ++I) {
    277         if (first) {
    278           os << ' '; first = false;
    279         }
    280         else
    281           os << ", ";
    282 
    283         (*I).dumpToStream(os);
    284       }
    285       os << "}";
    286       break;
    287     }
    288     case nonloc::LazyCompoundValKind: {
    289       const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
    290       os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
    291          << ',' << C.getRegion()
    292          << '}';
    293       break;
    294     }
    295     default:
    296       assert (false && "Pretty-printed not implemented for this NonLoc.");
    297       break;
    298   }
    299 }
    300 
    301 void Loc::dumpToStream(raw_ostream &os) const {
    302   switch (getSubKind()) {
    303     case loc::ConcreteIntKind:
    304       os << cast<loc::ConcreteInt>(this)->getValue().getZExtValue() << " (Loc)";
    305       break;
    306     case loc::GotoLabelKind:
    307       os << "&&" << cast<loc::GotoLabel>(this)->getLabel()->getName();
    308       break;
    309     case loc::MemRegionKind:
    310       os << '&' << cast<loc::MemRegionVal>(this)->getRegion()->getString();
    311       break;
    312     case loc::ObjCPropRefKind: {
    313       const ObjCPropertyRefExpr *E = cast<loc::ObjCPropRef>(this)->getPropRefExpr();
    314       os << "objc-prop{";
    315       if (E->isSuperReceiver())
    316         os << "super.";
    317       else if (E->getBase())
    318         os << "<base>.";
    319 
    320       if (E->isImplicitProperty())
    321         os << E->getImplicitPropertyGetter()->getSelector().getAsString();
    322       else
    323         os << E->getExplicitProperty()->getName();
    324 
    325       os << "}";
    326       break;
    327     }
    328     default:
    329       llvm_unreachable("Pretty-printing not implemented for this Loc.");
    330   }
    331 }
    332