diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/MemRegion.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/MemRegion.cpp | 214 | 
1 files changed, 122 insertions, 92 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp index 0c126a632f74..16db6b249dc9 100644 --- a/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -39,6 +39,7 @@  #include "llvm/ADT/SmallString.h"  #include "llvm/ADT/StringRef.h"  #include "llvm/ADT/Twine.h" +#include "llvm/ADT/iterator_range.h"  #include "llvm/Support/Allocator.h"  #include "llvm/Support/Casting.h"  #include "llvm/Support/CheckedArithmetic.h" @@ -73,8 +74,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1,    auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));    if (!R) { -    R = A.Allocate<RegionTy>(); -    new (R) RegionTy(arg1, superRegion); +    R = new (A) RegionTy(arg1, superRegion);      Regions.InsertNode(R, InsertPos);    } @@ -90,8 +90,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,    auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));    if (!R) { -    R = A.Allocate<RegionTy>(); -    new (R) RegionTy(arg1, arg2, superRegion); +    R = new (A) RegionTy(arg1, arg2, superRegion);      Regions.InsertNode(R, InsertPos);    } @@ -109,8 +108,7 @@ RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2,    auto *R = cast_or_null<RegionTy>(Regions.FindNodeOrInsertPos(ID, InsertPos));    if (!R) { -    R = A.Allocate<RegionTy>(); -    new (R) RegionTy(arg1, arg2, arg3, superRegion); +    R = new (A) RegionTy(arg1, arg2, arg3, superRegion);      Regions.InsertNode(R, InsertPos);    } @@ -161,6 +159,18 @@ const StackFrameContext *VarRegion::getStackFrame() const {    return SSR ? SSR->getStackFrame() : nullptr;  } +const StackFrameContext * +CXXLifetimeExtendedObjectRegion::getStackFrame() const { +  const auto *SSR = dyn_cast<StackSpaceRegion>(getMemorySpace()); +  return SSR ? SSR->getStackFrame() : nullptr; +} + +const StackFrameContext *CXXTempObjectRegion::getStackFrame() const { +  assert(isa<StackSpaceRegion>(getMemorySpace()) && +         "A temporary object can only be allocated on the stack"); +  return cast<StackSpaceRegion>(getMemorySpace())->getStackFrame(); +} +  ObjCIvarRegion::ObjCIvarRegion(const ObjCIvarDecl *ivd, const SubRegion *sReg)      : DeclRegion(sReg, ObjCIvarRegionKind), IVD(ivd) {    assert(IVD); @@ -392,6 +402,20 @@ void CXXTempObjectRegion::Profile(llvm::FoldingSetNodeID &ID) const {    ProfileRegion(ID, Ex, getSuperRegion());  } +void CXXLifetimeExtendedObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID, +                                                    const Expr *E, +                                                    const ValueDecl *D, +                                                    const MemRegion *sReg) { +  ID.AddPointer(E); +  ID.AddPointer(D); +  ID.AddPointer(sReg); +} + +void CXXLifetimeExtendedObjectRegion::Profile( +    llvm::FoldingSetNodeID &ID) const { +  ProfileRegion(ID, Ex, ExD, getSuperRegion()); +} +  void CXXBaseObjectRegion::ProfileRegion(llvm::FoldingSetNodeID &ID,                                          const CXXRecordDecl *RD,                                          bool IsVirtual, @@ -468,11 +492,9 @@ void BlockCodeRegion::dumpToStream(raw_ostream &os) const {  void BlockDataRegion::dumpToStream(raw_ostream &os) const {    os << "block_data{" << BC;    os << "; "; -  for (BlockDataRegion::referenced_vars_iterator -         I = referenced_vars_begin(), -         E = referenced_vars_end(); I != E; ++I) -    os << "(" << I.getCapturedRegion() << "<-" << -                 I.getOriginalRegion() << ") "; +  for (auto Var : referenced_vars()) +    os << "(" << Var.getCapturedRegion() << "<-" << Var.getOriginalRegion() +       << ") ";    os << '}';  } @@ -486,6 +508,16 @@ void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const {       << "S" << Ex->getID(getContext()) << '}';  } +void CXXLifetimeExtendedObjectRegion::dumpToStream(raw_ostream &os) const { +  os << "lifetime_extended_object{" << getValueType() << ", "; +  if (const IdentifierInfo *ID = ExD->getIdentifier()) +    os << ID->getName(); +  else +    os << "D" << ExD->getID(); +  os << ", " +     << "S" << Ex->getID(getContext()) << '}'; +} +  void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const {    os << "Base{" << superRegion << ',' << getDecl()->getName() << '}';  } @@ -712,21 +744,17 @@ std::string MemRegion::getDescriptiveName(bool UseQuotes) const {  }  SourceRange MemRegion::sourceRange() const { -  const auto *const VR = dyn_cast<VarRegion>(this->getBaseRegion()); -  const auto *const FR = dyn_cast<FieldRegion>(this); -    // Check for more specific regions first. -  // FieldRegion -  if (FR) { +  if (auto *FR = dyn_cast<FieldRegion>(this)) {      return FR->getDecl()->getSourceRange();    } -  // VarRegion -  else if (VR) { + +  if (auto *VR = dyn_cast<VarRegion>(this->getBaseRegion())) {      return VR->getDecl()->getSourceRange();    } +    // Return invalid source range (can be checked by client). -  else -    return {}; +  return {};  }  //===----------------------------------------------------------------------===// @@ -750,6 +778,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,    case MemRegion::CXXBaseObjectRegionKind:    case MemRegion::CXXDerivedObjectRegionKind:    case MemRegion::CXXTempObjectRegionKind: +  case MemRegion::CXXLifetimeExtendedObjectRegionKind:    case MemRegion::CXXThisRegionKind:    case MemRegion::ObjCIvarRegionKind:    case MemRegion::NonParamVarRegionKind: @@ -776,49 +805,46 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,      // We currently don't model flexible array members (FAMs), which are:      //  - int array[]; of IncompleteArrayType      //  - int array[0]; of ConstantArrayType with size 0 -    //  - int array[1]; of ConstantArrayType with size 1 (*) -    // (*): Consider single element array object members as FAM candidates only -    //      if the consider-single-element-arrays-as-flexible-array-members -    //      analyzer option is true. +    //  - int array[1]; of ConstantArrayType with size 1      // https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html -    const auto isFlexibleArrayMemberCandidate = [this, -                                                 &SVB](QualType Ty) -> bool { -      const ArrayType *AT = Ctx.getAsArrayType(Ty); +    const auto isFlexibleArrayMemberCandidate = +        [this](const ArrayType *AT) -> bool {        if (!AT)          return false; -      if (isa<IncompleteArrayType>(AT)) -        return true; -      if (const auto *CAT = dyn_cast<ConstantArrayType>(AT)) { -        using FAMKind = LangOptions::StrictFlexArraysLevelKind; -        const FAMKind StrictFlexArraysLevel = +      auto IsIncompleteArray = [](const ArrayType *AT) { +        return isa<IncompleteArrayType>(AT); +      }; +      auto IsArrayOfZero = [](const ArrayType *AT) { +        const auto *CAT = dyn_cast<ConstantArrayType>(AT); +        return CAT && CAT->getSize() == 0; +      }; +      auto IsArrayOfOne = [](const ArrayType *AT) { +        const auto *CAT = dyn_cast<ConstantArrayType>(AT); +        return CAT && CAT->getSize() == 1; +      }; + +      using FAMKind = LangOptions::StrictFlexArraysLevelKind; +      const FAMKind StrictFlexArraysLevel =            Ctx.getLangOpts().getStrictFlexArraysLevel(); -        const AnalyzerOptions &Opts = SVB.getAnalyzerOptions(); -        const llvm::APInt &Size = CAT->getSize(); - -        if (StrictFlexArraysLevel <= FAMKind::ZeroOrIncomplete && Size.isZero()) -          return true; - -        // The "-fstrict-flex-arrays" should have precedence over -        // consider-single-element-arrays-as-flexible-array-members -        // analyzer-config when checking single element arrays. -        if (StrictFlexArraysLevel == FAMKind::Default) { -          // FIXME: After clang-17 released, we should remove this branch. -          if (Opts.ShouldConsiderSingleElementArraysAsFlexibleArrayMembers && -              Size.isOne()) -            return true; -        } else { -          // -fstrict-flex-arrays was specified, since it's not the default, so -          // ignore analyzer-config. -          if (StrictFlexArraysLevel <= FAMKind::OneZeroOrIncomplete && -              Size.isOne()) -            return true; -        } -      } -      return false; + +      // "Default": Any trailing array member is a FAM. +      // Since we cannot tell at this point if this array is a trailing member +      // or not, let's just do the same as for "OneZeroOrIncomplete". +      if (StrictFlexArraysLevel == FAMKind::Default) +        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT); + +      if (StrictFlexArraysLevel == FAMKind::OneZeroOrIncomplete) +        return IsArrayOfOne(AT) || IsArrayOfZero(AT) || IsIncompleteArray(AT); + +      if (StrictFlexArraysLevel == FAMKind::ZeroOrIncomplete) +        return IsArrayOfZero(AT) || IsIncompleteArray(AT); + +      assert(StrictFlexArraysLevel == FAMKind::IncompleteOnly); +      return IsIncompleteArray(AT);      }; -    if (isFlexibleArrayMemberCandidate(Ty)) +    if (isFlexibleArrayMemberCandidate(Ctx.getAsArrayType(Ty)))        return UnknownVal();      return Size; @@ -838,8 +864,7 @@ DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,  template <typename REG>  const REG *MemRegionManager::LazyAllocate(REG*& region) {    if (!region) { -    region = A.Allocate<REG>(); -    new (region) REG(*this); +    region = new (A) REG(*this);    }    return region; @@ -848,8 +873,7 @@ const REG *MemRegionManager::LazyAllocate(REG*& region) {  template <typename REG, typename ARG>  const REG *MemRegionManager::LazyAllocate(REG*& region, ARG a) {    if (!region) { -    region = A.Allocate<REG>(); -    new (region) REG(this, a); +    region = new (A) REG(this, a);    }    return region; @@ -863,8 +887,7 @@ MemRegionManager::getStackLocalsRegion(const StackFrameContext *STC) {    if (R)      return R; -  R = A.Allocate<StackLocalsSpaceRegion>(); -  new (R) StackLocalsSpaceRegion(*this, STC); +  R = new (A) StackLocalsSpaceRegion(*this, STC);    return R;  } @@ -876,8 +899,7 @@ MemRegionManager::getStackArgumentsRegion(const StackFrameContext *STC) {    if (R)      return R; -  R = A.Allocate<StackArgumentsSpaceRegion>(); -  new (R) StackArgumentsSpaceRegion(*this, STC); +  R = new (A) StackArgumentsSpaceRegion(*this, STC);    return R;  } @@ -898,8 +920,7 @@ const GlobalsSpaceRegion    if (R)      return R; -  R = A.Allocate<StaticGlobalSpaceRegion>(); -  new (R) StaticGlobalSpaceRegion(*this, CR); +  R = new (A) StaticGlobalSpaceRegion(*this, CR);    return R;  } @@ -945,13 +966,11 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,      if (const auto *BC = dyn_cast<BlockInvocationContext>(LC)) {        const auto *BR = static_cast<const BlockDataRegion *>(BC->getData());        // 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) { -        const TypedValueRegion *OrigR = I.getOriginalRegion(); +      for (auto Var : BR->referenced_vars()) { +        const TypedValueRegion *OrigR = Var.getOriginalRegion();          if (const auto *VR = dyn_cast<VarRegion>(OrigR)) {            if (VR->getDecl() == VD) -            return cast<VarRegion>(I.getCapturedRegion()); +            return cast<VarRegion>(Var.getCapturedRegion());          }        }      } @@ -1058,13 +1077,16 @@ const VarRegion *MemRegionManager::getVarRegion(const VarDecl *D,      }    } -  return getSubRegion<NonParamVarRegion>(D, sReg); +  return getNonParamVarRegion(D, sReg);  }  const NonParamVarRegion *  MemRegionManager::getNonParamVarRegion(const VarDecl *D,                                         const MemRegion *superR) { +  // Prefer the definition over the canonical decl as the canonical form.    D = D->getCanonicalDecl(); +  if (const VarDecl *Def = D->getDefinition()) +    D = Def;    return getSubRegion<NonParamVarRegion>(D, superR);  } @@ -1109,12 +1131,6 @@ MemRegionManager::getBlockDataRegion(const BlockCodeRegion *BC,    return getSubRegion<BlockDataRegion>(BC, LC, blockCount, sReg);  } -const CXXTempObjectRegion * -MemRegionManager::getCXXStaticTempObjectRegion(const Expr *Ex) { -  return getSubRegion<CXXTempObjectRegion>( -      Ex, getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); -} -  const CompoundLiteralRegion*  MemRegionManager::getCompoundLiteralRegion(const CompoundLiteralExpr *CL,                                             const LocationContext *LC) { @@ -1145,8 +1161,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx,    auto *R = cast_or_null<ElementRegion>(data);    if (!R) { -    R = A.Allocate<ElementRegion>(); -    new (R) ElementRegion(T, Idx, superRegion); +    R = new (A) ElementRegion(T, Idx, superRegion);      Regions.InsertNode(R, InsertPos);    } @@ -1197,6 +1212,23 @@ MemRegionManager::getCXXTempObjectRegion(Expr const *E,    return getSubRegion<CXXTempObjectRegion>(E, getStackLocalsRegion(SFC));  } +const CXXLifetimeExtendedObjectRegion * +MemRegionManager::getCXXLifetimeExtendedObjectRegion( +    const Expr *Ex, const ValueDecl *VD, const LocationContext *LC) { +  const StackFrameContext *SFC = LC->getStackFrame(); +  assert(SFC); +  return getSubRegion<CXXLifetimeExtendedObjectRegion>( +      Ex, VD, getStackLocalsRegion(SFC)); +} + +const CXXLifetimeExtendedObjectRegion * +MemRegionManager::getCXXStaticLifetimeExtendedObjectRegion( +    const Expr *Ex, const ValueDecl *VD) { +  return getSubRegion<CXXLifetimeExtendedObjectRegion>( +      Ex, VD, +      getGlobalsRegion(MemRegion::GlobalInternalSpaceRegionKind, nullptr)); +} +  /// Checks whether \p BaseClass is a valid virtual or direct non-virtual base  /// class of the type of \p Super.  static bool isValidBaseClass(const CXXRecordDecl *BaseClass, @@ -1283,7 +1315,7 @@ const MemSpaceRegion *MemRegion::getMemorySpace() const {      SR = dyn_cast<SubRegion>(R);    } -  return dyn_cast<MemSpaceRegion>(R); +  return cast<MemSpaceRegion>(R);  }  bool MemRegion::hasStackStorage() const { @@ -1298,10 +1330,6 @@ bool MemRegion::hasStackParametersStorage() const {    return isa<StackArgumentsSpaceRegion>(getMemorySpace());  } -bool MemRegion::hasGlobalsOrParametersStorage() const { -  return isa<StackArgumentsSpaceRegion, GlobalsSpaceRegion>(getMemorySpace()); -} -  // Strips away all elements and fields.  // Returns the base region of them.  const MemRegion *MemRegion::getBaseRegion() const { @@ -1474,6 +1502,7 @@ static RegionOffset calculateOffset(const MemRegion *R) {      case MemRegion::NonParamVarRegionKind:      case MemRegion::ParamVarRegionKind:      case MemRegion::CXXTempObjectRegionKind: +    case MemRegion::CXXLifetimeExtendedObjectRegionKind:        // Usual base regions.        goto Finish; @@ -1664,10 +1693,8 @@ void BlockDataRegion::LazyInitializeReferencedVars() {    using VarVec = BumpVector<const MemRegion *>; -  auto *BV = A.Allocate<VarVec>(); -  new (BV) VarVec(BC, NumBlockVars); -  auto *BVOriginal = A.Allocate<VarVec>(); -  new (BVOriginal) VarVec(BC, NumBlockVars); +  auto *BV = new (A) VarVec(BC, NumBlockVars); +  auto *BVOriginal = new (A) VarVec(BC, NumBlockVars);    for (const auto *VD : ReferencedBlockVars) {      const VarRegion *VR = nullptr; @@ -1715,10 +1742,13 @@ BlockDataRegion::referenced_vars_end() const {                                                     VecOriginal->end());  } +llvm::iterator_range<BlockDataRegion::referenced_vars_iterator> +BlockDataRegion::referenced_vars() const { +  return llvm::make_range(referenced_vars_begin(), referenced_vars_end()); +} +  const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const { -  for (referenced_vars_iterator I = referenced_vars_begin(), -                                E = referenced_vars_end(); -       I != E; ++I) { +  for (const auto &I : referenced_vars()) {      if (I.getCapturedRegion() == R)        return I.getOriginalRegion();    }  | 
