diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/MemRegion.cpp')
| -rw-r--r-- | lib/StaticAnalyzer/Core/MemRegion.cpp | 274 | 
1 files changed, 231 insertions, 43 deletions
diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index ed94c79df1b7..62e602a7e1e1 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -179,7 +179,7 @@ const StackFrameContext *VarRegion::getStackFrame() const {  // Region extents.  //===----------------------------------------------------------------------===// -DefinedOrUnknownSVal DeclRegion::getExtent(SValBuilder &svalBuilder) const { +DefinedOrUnknownSVal TypedValueRegion::getExtent(SValBuilder &svalBuilder) const {    ASTContext &Ctx = svalBuilder.getContext();    QualType T = getDesugaredValueType(Ctx); @@ -470,7 +470,7 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {  }  void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { -  os << "base " << decl->getName(); +  os << "base{" << superRegion << ',' << decl->getName() << '}';  }  void CXXThisRegion::dumpToStream(raw_ostream &os) const { @@ -518,10 +518,6 @@ void StaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const {    os << "StaticGlobalsMemSpace{" << CR << '}';  } -void NonStaticGlobalSpaceRegion::dumpToStream(raw_ostream &os) const { -  os << "NonStaticGlobalSpaceRegion"; -} -  void GlobalInternalSpaceRegion::dumpToStream(raw_ostream &os) const {    os << "GlobalInternalSpaceRegion";  } @@ -534,17 +530,45 @@ void GlobalImmutableSpaceRegion::dumpToStream(raw_ostream &os) const {    os << "GlobalImmutableSpaceRegion";  } -void MemRegion::dumpPretty(raw_ostream &os) const { +void HeapSpaceRegion::dumpToStream(raw_ostream &os) const { +  os << "HeapSpaceRegion"; +} + +void UnknownSpaceRegion::dumpToStream(raw_ostream &os) const { +  os << "UnknownSpaceRegion"; +} + +void StackArgumentsSpaceRegion::dumpToStream(raw_ostream &os) const { +  os << "StackArgumentsSpaceRegion"; +} + +void StackLocalsSpaceRegion::dumpToStream(raw_ostream &os) const { +  os << "StackLocalsSpaceRegion"; +} + +bool MemRegion::canPrintPretty() const { +  return false; +} + +void MemRegion::printPretty(raw_ostream &os) const {    return;  } -void VarRegion::dumpPretty(raw_ostream &os) const { +bool VarRegion::canPrintPretty() const { +  return true; +} + +void VarRegion::printPretty(raw_ostream &os) const {    os << getDecl()->getName();  } -void FieldRegion::dumpPretty(raw_ostream &os) const { -  superRegion->dumpPretty(os); -  os << "->" << getDecl(); +bool FieldRegion::canPrintPretty() const { +  return superRegion->canPrintPretty(); +} + +void FieldRegion::printPretty(raw_ostream &os) const { +  superRegion->printPretty(os); +  os << "." << getDecl()->getName();  }  //===----------------------------------------------------------------------===// @@ -643,6 +667,37 @@ MemRegionManager::getObjCStringRegion(const ObjCStringLiteral* Str){    return getSubRegion<ObjCStringRegion>(Str, getGlobalsRegion());  } +/// Look through a chain of LocationContexts to either find the +/// StackFrameContext that matches a DeclContext, or find a VarRegion +/// for a variable captured by a block. +static llvm::PointerUnion<const StackFrameContext *, const VarRegion *> +getStackOrCaptureRegionForDeclContext(const LocationContext *LC, +                                      const DeclContext *DC, +                                      const VarDecl *VD) { +  while (LC) { +    if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LC)) { +      if (cast<DeclContext>(SFC->getDecl()) == DC) +        return SFC; +    } +    if (const BlockInvocationContext *BC = +        dyn_cast<BlockInvocationContext>(LC)) { +      const BlockDataRegion *BR = +        static_cast<const BlockDataRegion*>(BC->getContextData()); +      // FIXME: This can be made more efficient. +      for (BlockDataRegion::referenced_vars_iterator +           I = BR->referenced_vars_begin(), +           E = BR->referenced_vars_end(); I != E; ++I) { +        if (const VarRegion *VR = dyn_cast<VarRegion>(I.getOriginalRegion())) +          if (VR->getDecl() == VD) +            return cast<VarRegion>(I.getCapturedRegion()); +      } +    } +     +    LC = LC->getParent(); +  } +  return (const StackFrameContext*)0; +} +  const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,                                                  const LocationContext *LC) {    const MemRegion *sReg = 0; @@ -675,7 +730,13 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,      // FIXME: Once we implement scope handling, we will need to properly lookup      // 'D' to the proper LocationContext.      const DeclContext *DC = D->getDeclContext(); -    const StackFrameContext *STC = LC->getStackFrameForDeclContext(DC); +    llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V = +      getStackOrCaptureRegionForDeclContext(LC, DC, D); +     +    if (V.is<const VarRegion*>()) +      return V.get<const VarRegion*>(); +     +    const StackFrameContext *STC = V.get<const StackFrameContext*>();      if (!STC)        sReg = getUnknownRegion(); @@ -800,6 +861,10 @@ const SymbolicRegion *MemRegionManager::getSymbolicRegion(SymbolRef sym) {    return getSubRegion<SymbolicRegion>(sym, getUnknownRegion());  } +const SymbolicRegion *MemRegionManager::getSymbolicHeapRegion(SymbolRef Sym) { +  return getSubRegion<SymbolicRegion>(Sym, getHeapRegion()); +} +  const FieldRegion*  MemRegionManager::getFieldRegion(const FieldDecl *d,                                   const MemRegion* superRegion){ @@ -823,6 +888,37 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,  const CXXBaseObjectRegion *  MemRegionManager::getCXXBaseObjectRegion(const CXXRecordDecl *decl,                                           const MemRegion *superRegion) { +  // Check that the base class is actually a direct base of this region. +  if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(superRegion)) { +    if (const CXXRecordDecl *Class = TVR->getValueType()->getAsCXXRecordDecl()){ +      if (Class->isVirtuallyDerivedFrom(decl)) { +        // Virtual base regions should not be layered, since the layout rules +        // are different. +        while (const CXXBaseObjectRegion *Base = +                 dyn_cast<CXXBaseObjectRegion>(superRegion)) { +          superRegion = Base->getSuperRegion(); +        } +        assert(superRegion && !isa<MemSpaceRegion>(superRegion)); + +      } else { +        // Non-virtual bases should always be direct bases. +#ifndef NDEBUG +        bool FoundBase = false; +        for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), +                                                      E = Class->bases_end(); +             I != E; ++I) { +          if (I->getType()->getAsCXXRecordDecl() == decl) { +            FoundBase = true; +            break; +          } +        } + +        assert(FoundBase && "Not a direct base class of this region"); +#endif +      } +    } +  } +    return getSubRegion<CXXBaseObjectRegion>(decl, superRegion);  } @@ -898,24 +994,26 @@ const MemRegion *MemRegion::getBaseRegion() const {  // View handling.  //===----------------------------------------------------------------------===// -const MemRegion *MemRegion::StripCasts() const { +const MemRegion *MemRegion::StripCasts(bool StripBaseCasts) const {    const MemRegion *R = this;    while (true) { -    if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { -      // FIXME: generalize.  Essentially we want to strip away ElementRegions -      // that were layered on a symbolic region because of casts.  We only -      // want to strip away ElementRegions, however, where the index is 0. -      SVal index = ER->getIndex(); -      if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&index)) { -        if (CI->getValue().getSExtValue() == 0) { -          R = ER->getSuperRegion(); -          continue; -        } -      } +    switch (R->getKind()) { +    case ElementRegionKind: { +      const ElementRegion *ER = cast<ElementRegion>(R); +      if (!ER->getIndex().isZeroConstant()) +        return R; +      R = ER->getSuperRegion(); +      break; +    } +    case CXXBaseObjectRegionKind: +      if (!StripBaseCasts) +        return R; +      R = cast<CXXBaseObjectRegion>(R)->getSuperRegion(); +      break; +    default: +      return R;      } -    break;    } -  return R;  }  // FIXME: Merge with the implementation of the same method in Store.cpp @@ -973,12 +1071,14 @@ RegionRawOffset ElementRegion::getAsArrayOffset() const {  RegionOffset MemRegion::getAsOffset() const {    const MemRegion *R = this; +  const MemRegion *SymbolicOffsetBase = 0;    int64_t Offset = 0;    while (1) {      switch (R->getKind()) {      default: -      return RegionOffset(0); +      return RegionOffset(R, RegionOffset::Symbolic); +      case SymbolicRegionKind:      case AllocaRegionKind:      case CompoundLiteralRegionKind: @@ -987,31 +1087,95 @@ RegionOffset MemRegion::getAsOffset() const {      case VarRegionKind:      case CXXTempObjectRegionKind:        goto Finish; + +    case ObjCIvarRegionKind: +      // This is a little strange, but it's a compromise between +      // ObjCIvarRegions having unknown compile-time offsets (when using the +      // non-fragile runtime) and yet still being distinct, non-overlapping +      // regions. Thus we treat them as "like" base regions for the purposes +      // of computing offsets. +      goto Finish; + +    case CXXBaseObjectRegionKind: { +      const CXXBaseObjectRegion *BOR = cast<CXXBaseObjectRegion>(R); +      R = BOR->getSuperRegion(); + +      QualType Ty; +      if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) { +        Ty = TVR->getDesugaredValueType(getContext()); +      } else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) { +        // If our base region is symbolic, we don't know what type it really is. +        // Pretend the type of the symbol is the true dynamic type. +        // (This will at least be self-consistent for the life of the symbol.) +        Ty = SR->getSymbol()->getType(getContext())->getPointeeType(); +      } +       +      const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); +      if (!Child) { +        // We cannot compute the offset of the base class. +        SymbolicOffsetBase = R; +      } + +      // Don't bother calculating precise offsets if we already have a +      // symbolic offset somewhere in the chain. +      if (SymbolicOffsetBase) +        continue; + +      const ASTRecordLayout &Layout = getContext().getASTRecordLayout(Child); + +      CharUnits BaseOffset; +      const CXXRecordDecl *Base = BOR->getDecl(); +      if (Child->isVirtuallyDerivedFrom(Base)) +        BaseOffset = Layout.getVBaseClassOffset(Base); +      else +        BaseOffset = Layout.getBaseClassOffset(Base); + +      // The base offset is in chars, not in bits. +      Offset += BaseOffset.getQuantity() * getContext().getCharWidth(); +      break; +    }      case ElementRegionKind: {        const ElementRegion *ER = cast<ElementRegion>(R); -      QualType EleTy = ER->getValueType(); +      R = ER->getSuperRegion(); -      if (!IsCompleteType(getContext(), EleTy)) -        return RegionOffset(0); +      QualType EleTy = ER->getValueType(); +      if (!IsCompleteType(getContext(), EleTy)) { +        // We cannot compute the offset of the base class. +        SymbolicOffsetBase = R; +        continue; +      }        SVal Index = ER->getIndex();        if (const nonloc::ConcreteInt *CI=dyn_cast<nonloc::ConcreteInt>(&Index)) { +        // Don't bother calculating precise offsets if we already have a +        // symbolic offset somewhere in the chain.  +        if (SymbolicOffsetBase) +          continue; +          int64_t i = CI->getValue().getSExtValue(); -        CharUnits Size = getContext().getTypeSizeInChars(EleTy); -        Offset += i * Size.getQuantity() * 8; +        // This type size is in bits. +        Offset += i * getContext().getTypeSize(EleTy);        } else {          // We cannot compute offset for non-concrete index. -        return RegionOffset(0); +        SymbolicOffsetBase = R;        } -      R = ER->getSuperRegion();        break;      }      case FieldRegionKind: {        const FieldRegion *FR = cast<FieldRegion>(R); +      R = FR->getSuperRegion(); +        const RecordDecl *RD = FR->getDecl()->getParent(); -      if (!RD->isCompleteDefinition()) +      if (!RD->isCompleteDefinition()) {          // We cannot compute offset for incomplete type. -        return RegionOffset(0); +        SymbolicOffsetBase = R; +      } + +      // Don't bother calculating precise offsets if we already have a +      // symbolic offset somewhere in the chain. +      if (SymbolicOffsetBase) +        continue; +        // Get the field number.        unsigned idx = 0;        for (RecordDecl::field_iterator FI = RD->field_begin(),  @@ -1022,13 +1186,14 @@ RegionOffset MemRegion::getAsOffset() const {        const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);        // This is offset in bits.        Offset += Layout.getFieldOffset(idx); -      R = FR->getSuperRegion();        break;      }      }    }   Finish: +  if (SymbolicOffsetBase) +    return RegionOffset(SymbolicOffsetBase, RegionOffset::Symbolic);    return RegionOffset(R, Offset);  } @@ -1056,26 +1221,37 @@ void BlockDataRegion::LazyInitializeReferencedVars() {    typedef BumpVector<const MemRegion*> VarVec;    VarVec *BV = (VarVec*) A.Allocate<VarVec>();    new (BV) VarVec(BC, E - I); +  VarVec *BVOriginal = (VarVec*) A.Allocate<VarVec>(); +  new (BVOriginal) VarVec(BC, E - I);    for ( ; I != E; ++I) {      const VarDecl *VD = *I;      const VarRegion *VR = 0; +    const VarRegion *OriginalVR = 0; -    if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) +    if (!VD->getAttr<BlocksAttr>() && VD->hasLocalStorage()) {        VR = MemMgr.getVarRegion(VD, this); +      OriginalVR = MemMgr.getVarRegion(VD, LC); +    }      else { -      if (LC) +      if (LC) {          VR = MemMgr.getVarRegion(VD, LC); +        OriginalVR = VR; +      }        else {          VR = MemMgr.getVarRegion(VD, MemMgr.getUnknownRegion()); +        OriginalVR = MemMgr.getVarRegion(VD, LC);        }      }      assert(VR); +    assert(OriginalVR);      BV->push_back(VR, BC); +    BVOriginal->push_back(OriginalVR, BC);    }    ReferencedVars = BV; +  OriginalVars = BVOriginal;  }  BlockDataRegion::referenced_vars_iterator @@ -1085,8 +1261,14 @@ BlockDataRegion::referenced_vars_begin() const {    BumpVector<const MemRegion*> *Vec =      static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); -  return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? -                                                   NULL : Vec->begin()); +  if (Vec == (void*) 0x1) +    return BlockDataRegion::referenced_vars_iterator(0, 0); +   +  BumpVector<const MemRegion*> *VecOriginal = +    static_cast<BumpVector<const MemRegion*>*>(OriginalVars); +   +  return BlockDataRegion::referenced_vars_iterator(Vec->begin(), +                                                   VecOriginal->begin());  }  BlockDataRegion::referenced_vars_iterator @@ -1096,6 +1278,12 @@ BlockDataRegion::referenced_vars_end() const {    BumpVector<const MemRegion*> *Vec =      static_cast<BumpVector<const MemRegion*>*>(ReferencedVars); -  return BlockDataRegion::referenced_vars_iterator(Vec == (void*) 0x1 ? -                                                   NULL : Vec->end()); +  if (Vec == (void*) 0x1) +    return BlockDataRegion::referenced_vars_iterator(0, 0); +   +  BumpVector<const MemRegion*> *VecOriginal = +    static_cast<BumpVector<const MemRegion*>*>(OriginalVars); + +  return BlockDataRegion::referenced_vars_iterator(Vec->end(), +                                                   VecOriginal->end());  }  | 
