Index: llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h =================================================================== --- llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -1180,6 +1180,16 @@ /// a specified VarDecl and LocationContext. const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC); +private: + /// Retrieve or create the memory region + /// associated with a VarDecl for a global variable. + const MemRegion *getMemSpaceForGlobalVariable(const VarDecl *D); + + /// Retrieve or create the memory region + /// associated with a specified VarDecl and LocationContext. + const MemRegion *getMemSpaceForLocalVariable(const VarDecl *D, llvm::PointerUnion &V); + +public: /// getVarRegion - Retrieve or create the memory region associated with /// a specified VarDecl and super region. const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR); Index: llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ llvm/tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -766,34 +766,76 @@ return (const StackFrameContext *)nullptr; } +const MemRegion* MemRegionManager::getMemSpaceForGlobalVariable(const VarDecl *D) { + assert(D->hasGlobalStorage()); + assert(!D->isStaticLocal()); + // First handle the globals defined in system headers. + if (C.getSourceManager().isInSystemHeader(D->getLocation())) { + // Whitelist the system globals which often DO GET modified, assume the + // rest are immutable. + if (D->getName().find("errno") != StringRef::npos) + return getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); + + return getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); + } + // Treat other globals as GlobalInternal unless they are constants. + QualType GQT = D->getType(); + const Type *GT = GQT.getTypePtrOrNull(); + // TODO: We could walk the complex types here and see if everything is + // constified. + if (GT && GQT.isConstQualified() && GT->isArithmeticType()) + return getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); + + return getGlobalsRegion(); +} + +const MemRegion* MemRegionManager::getMemSpaceForLocalVariable(const VarDecl *D, llvm::PointerUnion &V) { + const StackFrameContext *STC = V.get(); + + if (!STC) + return getUnknownRegion(); + + if (D->hasLocalStorage()) { + return (isa(D) || isa(D) + ? static_cast(getStackArgumentsRegion(STC)) + : static_cast(getStackLocalsRegion(STC))); + } + assert(D->isStaticLocal()); + const Decl *STCD = STC->getDecl(); + if (isa(STCD) || isa(STCD)) + return getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, + getFunctionCodeRegion(cast(STCD))); + + else if (const BlockDecl *BD = dyn_cast(STCD)) { + // FIXME: The fallback type here is totally bogus -- though it should + // never be queried, it will prevent uniquing with the real + // BlockCodeRegion. Ideally we'd fix the AST so that we always had a + // signature. + QualType T; + if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) + T = TSI->getType(); + if (T.isNull()) + T = getContext().VoidTy; + if (!T->getAs()) + T = getContext().getFunctionNoProtoType(T); + T = getContext().getBlockPointerType(T); + + const BlockCodeRegion *BTR = + getBlockCodeRegion(BD, C.getCanonicalType(T), + STC->getAnalysisDeclContext()); + return getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, + BTR); + } + return getGlobalsRegion(); +} + const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, const LocationContext *LC) { const MemRegion *sReg = nullptr; if (D->hasGlobalStorage() && !D->isStaticLocal()) { + sReg = getMemSpaceForGlobalVariable(D); - // First handle the globals defined in system headers. - if (C.getSourceManager().isInSystemHeader(D->getLocation())) { - // Whitelist the system globals which often DO GET modified, assume the - // rest are immutable. - if (D->getName().find("errno") != StringRef::npos) - sReg = getGlobalsRegion(MemRegion::GlobalSystemSpaceRegionKind); - else - sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); - - // Treat other globals as GlobalInternal unless they are constants. - } else { - QualType GQT = D->getType(); - const Type *GT = GQT.getTypePtrOrNull(); - // TODO: We could walk the complex types here and see if everything is - // constified. - if (GT && GQT.isConstQualified() && GT->isArithmeticType()) - sReg = getGlobalsRegion(MemRegion::GlobalImmutableSpaceRegionKind); - else - sReg = getGlobalsRegion(); - } - - // Finally handle static locals. } else { // FIXME: Once we implement scope handling, we will need to properly lookup // 'D' to the proper LocationContext. @@ -804,49 +846,8 @@ if (V.is()) return V.get(); - const StackFrameContext *STC = V.get(); - - if (!STC) - sReg = getUnknownRegion(); - else { - if (D->hasLocalStorage()) { - sReg = isa(D) || isa(D) - ? static_cast(getStackArgumentsRegion(STC)) - : static_cast(getStackLocalsRegion(STC)); - } - else { - assert(D->isStaticLocal()); - const Decl *STCD = STC->getDecl(); - if (isa(STCD) || isa(STCD)) - sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, - getFunctionCodeRegion(cast(STCD))); - else if (const BlockDecl *BD = dyn_cast(STCD)) { - // FIXME: The fallback type here is totally bogus -- though it should - // never be queried, it will prevent uniquing with the real - // BlockCodeRegion. Ideally we'd fix the AST so that we always had a - // signature. - QualType T; - if (const TypeSourceInfo *TSI = BD->getSignatureAsWritten()) - T = TSI->getType(); - if (T.isNull()) - T = getContext().VoidTy; - if (!T->getAs()) - T = getContext().getFunctionNoProtoType(T); - T = getContext().getBlockPointerType(T); - - const BlockCodeRegion *BTR = - getBlockCodeRegion(BD, C.getCanonicalType(T), - STC->getAnalysisDeclContext()); - sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, - BTR); - } - else { - sReg = getGlobalsRegion(); - } - } - } + sReg = getMemSpaceForLocalVariable(D, V); } - return getSubRegion(D, sReg); }