Index: clang/include/clang/Analysis/AnalysisDeclContext.h =================================================================== --- clang/include/clang/Analysis/AnalysisDeclContext.h +++ clang/include/clang/Analysis/AnalysisDeclContext.h @@ -323,11 +323,13 @@ const CFGBlock *getCallSiteBlock() const { return Block; } - /// Return true if the current LocationContext has no caller context. - bool inTopFrame() const override { return getParent() == nullptr; } + unsigned getBlockCount() const { return BlockCount; } unsigned getIndex() const { return Index; } + /// Return true if the current LocationContext has no caller context. + bool inTopFrame() const override { return getParent() == nullptr; } + void Profile(llvm::FoldingSetNodeID &ID) override; static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *ctx, Index: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h =================================================================== --- clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h +++ clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h @@ -152,8 +152,9 @@ return "pointee of " + Visit(R->getSymbol()); } - std::string VisitAllocaRegion(const AllocaRegion *R) { - return "region allocated by '" + printStmt(R->getExpr()) + "'"; + std::string VisitMemoryBlockRegion(const MemoryBlockRegion *R) { + return "memory block region allocated by '" + printStmt(R->getAllocExpr()) + + "'"; } std::string VisitCompoundLiteralRegion(const CompoundLiteralRegion *R) { Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h @@ -128,6 +128,14 @@ const MemRegion *StripCasts(bool StripBaseAndDerivedCasts = true) const; + /// getExtent - Returns the size of the region in bytes. + virtual DefinedOrUnknownSVal getExtent() const { return UnknownVal(); } + + /// getExtent - Returns the size of the region in bytes. + virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { + return UnknownVal(); + } + /// If this is a symbolic region, returns the region. Otherwise, /// goes up the base chain looking for the first symbolic base region. const SymbolicRegion *getSymbolicBase() const; @@ -449,11 +457,6 @@ return superRegion; } - /// getExtent - Returns the size of the region in bytes. - virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const { - return UnknownVal(); - } - MemRegionManager* getMemRegionManager() const override; bool isSubRegionOf(const MemRegion* R) const override; @@ -467,39 +470,48 @@ // MemRegion subclasses. //===----------------------------------------------------------------------===// -/// AllocaRegion - A region that represents an untyped blob of bytes created -/// by a call to 'alloca'. -class AllocaRegion : public SubRegion { - friend class MemRegionManager; - - // Block counter. Used to distinguish different pieces of memory allocated by - // alloca at the same call site. - unsigned Cnt; - - const Expr *Ex; - - AllocaRegion(const Expr *ex, unsigned cnt, const MemSpaceRegion *superRegion) - : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) { - assert(Ex); - } - - static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr *Ex, - unsigned Cnt, const MemRegion *superRegion); - +/// A region that represents a block of memory. +class MemoryBlockRegion : public SubRegion { public: - const Expr *getExpr() const { return Ex; } + const Expr *getAllocExpr() const { return AllocExpr; } + const Decl *getAllocDecl() const { return AllocDecl; } + const Expr *getSizeExpr() const { return SizeExpr; } + + DefinedOrUnknownSVal getExtent() const override { return Size; } + DefinedOrUnknownSVal getExtent(SValBuilder &) const override { return Size; } bool isBoundable() const override { return true; } - DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const override; + void Profile(llvm::FoldingSetNodeID &ID) const override; - void Profile(llvm::FoldingSetNodeID& ID) const override; + static bool classof(const MemRegion *R) { + return R->getKind() == MemoryBlockRegionKind; + } void dumpToStream(raw_ostream &os) const override; - static bool classof(const MemRegion* R) { - return R->getKind() == AllocaRegionKind; - } +private: + MemoryBlockRegion(const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, + unsigned BlockCount, const MemSpaceRegion *superRegion) + : SubRegion(superRegion, MemoryBlockRegionKind), AllocExpr(AllocExpr), + AllocDecl(AllocDecl), SizeExpr(SizeExpr), Size(Size), + BlockCount(BlockCount) { + assert(AllocExpr || AllocDecl); + } + + static void ProfileRegion(llvm::FoldingSetNodeID &ID, const Expr *AllocExpr, + const Decl *AllocDecl, const Expr *SizeExpr, + DefinedOrUnknownSVal Size, unsigned BlockCount, + const MemRegion *superRegion); + + const Expr *AllocExpr; + const Decl *AllocDecl; + const Expr *SizeExpr; + DefinedOrUnknownSVal Size; + unsigned BlockCount; + + friend class MemRegionManager; }; /// TypedRegion - An abstract class representing regions that are typed. @@ -766,7 +778,7 @@ const SymbolRef sym; - SymbolicRegion(const SymbolRef s, const MemSpaceRegion *sreg) + SymbolicRegion(const SymbolRef s, const MemRegion *sreg) : SubRegion(sreg, SymbolicRegionKind), sym(s) { // Because pointer arithmetic is represented by ElementRegion layers, // the base symbol here should not contain any arithmetic. @@ -774,7 +786,8 @@ assert(s->getType()->isAnyPointerType() || s->getType()->isReferenceType() || s->getType()->isBlockPointerType()); - assert(isa(sreg) || isa(sreg)); + assert(isa(sreg) || isa(sreg) || + isa(sreg)); } public: @@ -936,7 +949,8 @@ // Other block variables appear within block data regions, // which, unlike everything else on this list, are not memory spaces. assert(isa(sReg) || isa(sReg) || - isa(sReg) || isa(sReg)); + isa(sReg) || isa(sReg) || + isa(sReg)); } static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl *VD, @@ -1244,6 +1258,7 @@ class MemRegionManager { ASTContext &C; llvm::BumpPtrAllocator& A; + SValBuilder &SVB; llvm::FoldingSet Regions; GlobalInternalSpaceRegion *InternalGlobals = nullptr; @@ -1262,7 +1277,9 @@ CodeSpaceRegion *code = nullptr; public: - MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator &a) : C(c), A(a) {} + MemRegionManager(ASTContext &Ctx, llvm::BumpPtrAllocator &Alloc, + SValBuilder &SVB) + : C(Ctx), A(Alloc), SVB(SVB) {} ~MemRegionManager(); ASTContext &getContext() { return C; } @@ -1295,10 +1312,6 @@ const CodeSpaceRegion *getCodeRegion(); - /// getAllocaRegion - Retrieve a region associated with a call to alloca(). - const AllocaRegion *getAllocaRegion(const Expr *Ex, unsigned Cnt, - const LocationContext *LC); - /// getCompoundLiteralRegion - Retrieve the region associated with a /// given CompoundLiteral. const CompoundLiteralRegion* @@ -1313,9 +1326,22 @@ /// Retrieve or create a "symbolic" memory region. const SymbolicRegion* getSymbolicRegion(SymbolRef Sym); - /// Return a unique symbolic region belonging to heap memory space. + /// \returns A unique symbolic region belonging to the generic "heap". const SymbolicRegion *getSymbolicHeapRegion(SymbolRef sym); + /// \returns A unique symbolic region to a memory block on the heap. + const SymbolicRegion * + getSymbolicHeapMemoryBlock(SymbolRef Sym, const Expr *AllocExpr, + const Decl *AllocDecl, const Expr *SizeExpr, + DefinedOrUnknownSVal Size, unsigned BlockCount); + + /// \returns A region associated with a block of memory on the stack. + const MemoryBlockRegion * + getStackMemoryBlockRegion(const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, + const LocationContext *LCtx, unsigned BlockCount, + bool IsArgument); + const StringRegion *getStringRegion(const StringLiteral *Str); const ObjCStringRegion *getObjCStringRegion(const ObjCStringLiteral *Str); @@ -1406,21 +1432,8 @@ const CXXTempObjectRegion *getCXXStaticTempObjectRegion(const Expr *Ex); private: - template - RegionTy* getSubRegion(const Arg1Ty arg1, - const SuperTy* superRegion); - - template - RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, - const SuperTy* superRegion); - - template - RegionTy* getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, - const Arg3Ty arg3, - const SuperTy* superRegion); + template + RegionTy *getSubRegion(ArgsTy &&... Args); template const REG* LazyAllocate(REG*& region); Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/Regions.def @@ -55,7 +55,7 @@ REGION_RANGE(MEMSPACES, CodeSpaceRegionKind, UnknownSpaceRegionKind) ABSTRACT_REGION(SubRegion, MemRegion) - REGION(AllocaRegion, SubRegion) + REGION(MemoryBlockRegion, SubRegion) REGION(SymbolicRegion, SubRegion) ABSTRACT_REGION(TypedRegion, SubRegion) REGION(BlockDataRegion, TypedRegion) Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h @@ -84,7 +84,7 @@ SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context, ProgramStateManager &stateMgr) : Context(context), BasicVals(context, alloc), - SymMgr(context, BasicVals, alloc), MemMgr(context, alloc), + SymMgr(context, BasicVals, alloc), MemMgr(context, alloc, *this), StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy), ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {} @@ -217,12 +217,21 @@ QualType type, unsigned visitCount); - /// Conjure a symbol representing heap allocated memory region. - /// - /// Note, the expression should represent a location. - DefinedOrUnknownSVal getConjuredHeapSymbolVal(const Expr *E, - const LocationContext *LCtx, - unsigned Count); + /// \returns A conjured symbol representing a heap allocated block of memory. + /// \note The expression \p AllocExpr should represent a location. + DefinedOrUnknownSVal + getConjuredHeapSymbolVal(const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, + const LocationContext *LCtx, unsigned BlockCount); + + /// \returns A stack allocated block of memory. + /// \note The expression \p AllocExpr should represent a location. + DefinedOrUnknownSVal getStackSymbolVal(const Expr *AllocExpr, + const Decl *AllocDecl, + const Expr *SizeExpr, + DefinedOrUnknownSVal Size, + const LocationContext *LCtx, + unsigned BlockCount, bool IsArgument); DefinedOrUnknownSVal getDerivedRegionValueSymbolVal( SymbolRef parentSymbol, const TypedValueRegion *region); Index: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -77,11 +77,6 @@ case Builtin::BI__builtin_alloca_with_align: case Builtin::BI__builtin_alloca: { - // FIXME: Refactor into StoreManager itself? - MemRegionManager& RM = C.getStoreManager().getRegionManager(); - const AllocaRegion* R = - RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); - // Set the extent of the region in bytes. This enables us to use the // SVal of the argument directly. If we save the extent in bits, we // cannot represent values like symbol*8. @@ -89,14 +84,12 @@ if (Size.isUndef()) return true; // Return true to model purity. - SValBuilder& svalBuilder = C.getSValBuilder(); - DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder); - DefinedOrUnknownSVal extentMatchesSizeArg = - svalBuilder.evalEQ(state, Extent, Size.castAs()); - state = state->assume(extentMatchesSizeArg, true); - assert(state && "The region should not have any previous constraints"); + SVal V = C.getSValBuilder().getStackSymbolVal( + CE, Call.getDecl(), Call.getArgExpr(0), + Size.castAs(), C.getLocationContext(), + C.blockCount(), /*IsArgument=*/false); - C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R))); + C.addTransition(state->BindExpr(CE, LCtx, V)); return true; } Index: clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -724,7 +724,7 @@ return state; case MemRegion::SymbolicRegionKind: - case MemRegion::AllocaRegionKind: + case MemRegion::MemoryBlockRegionKind: case MemRegion::VarRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: @@ -829,7 +829,7 @@ return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); } case MemRegion::SymbolicRegionKind: - case MemRegion::AllocaRegionKind: + case MemRegion::MemoryBlockRegionKind: case MemRegion::VarRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: Index: clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -199,7 +199,7 @@ static bool isBadDeallocationArgument(const MemRegion *Arg) { if (!Arg) return false; - return isa(Arg) || isa(Arg) || + return isa(Arg) || isa(Arg) || isa(Arg); } Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -461,8 +461,8 @@ /// \param [in] State The \c ProgramState right before allocation. /// \returns The ProgramState right after allocation. static ProgramStateRef MallocMemAux(CheckerContext &C, const CallExpr *CE, - SVal Size, SVal Init, - ProgramStateRef State, + const Expr *SizeExpr, SVal Size, + SVal Init, ProgramStateRef State, AllocationFamily Family = AF_Malloc); static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE, @@ -1162,7 +1162,7 @@ } else if (FunI == MemFunctionInfo.II_if_nameindex) { // Should we model this differently? We can allocate a fixed number of // elements with zeros in the last one. - State = MallocMemAux(C, CE, UnknownVal(), UnknownVal(), State, + State = MallocMemAux(C, CE, /*SizeExpr=*/nullptr, UnknownVal(), UnknownVal(), State, AF_IfNameIndex); } else if (FunI == MemFunctionInfo.II_if_freenameindex) { State = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocatedMemory); @@ -1192,7 +1192,7 @@ Init = SB.makeZeroVal(SB.getContext().CharTy); } SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); - State = MallocMemAux(C, CE, TotalSize, Init, State); + State = MallocMemAux(C, CE, CE->getArg(0), TotalSize, Init, State); State = ProcessZeroAllocCheck(C, CE, 0, State); State = ProcessZeroAllocCheck(C, CE, 1, State); } else if (FunI == MemFunctionInfo.II_g_realloc_n || @@ -1493,7 +1493,7 @@ return MallocMemAux(C, CE, CE->getArg(I->getASTIndex()), UndefinedVal(), State); } - return MallocMemAux(C, CE, UnknownVal(), UndefinedVal(), State); + return MallocMemAux(C, CE, /*SizeExpr=*/nullptr, UnknownVal(), UndefinedVal(), State); } ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, @@ -1504,14 +1504,14 @@ if (!State) return nullptr; - return MallocMemAux(C, CE, C.getSVal(SizeEx), Init, State, Family); + return MallocMemAux(C, CE, SizeEx, C.getSVal(SizeEx), Init, State, Family); } ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, - const CallExpr *CE, - SVal Size, SVal Init, - ProgramStateRef State, - AllocationFamily Family) { + const CallExpr *CE, + const Expr *SizeExpr, SVal Size, + SVal Init, ProgramStateRef State, + AllocationFamily Family) { if (!State) return nullptr; @@ -1525,8 +1525,11 @@ unsigned Count = C.blockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count) - .castAs(); + DefinedSVal RetVal = svalBuilder + .getConjuredHeapSymbolVal( + CE, /*AllocDecl=*/nullptr, SizeExpr, + Size.castAs(), LCtx, Count) + .castAs(); State = State->BindExpr(CE, C.getLocationContext(), RetVal); // Fill the region with the initialization value. @@ -1804,7 +1807,7 @@ // function, so UnknownSpaceRegion is always a possibility. // False negatives are better than false positives. - if (isa(R)) + if (isa(R)) ReportFreeAlloca(C, ArgVal, ArgExpr->getSourceRange()); else ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); @@ -2440,7 +2443,7 @@ // If the ptr is NULL and the size is not 0, the call is equivalent to // malloc(size). if (PrtIsNull && !SizeIsZero) { - ProgramStateRef stateMalloc = MallocMemAux(C, CE, TotalSize, + ProgramStateRef stateMalloc = MallocMemAux(C, CE, Arg1, TotalSize, UndefinedVal(), StatePtrIsNull); return stateMalloc; } @@ -2472,7 +2475,7 @@ if (ProgramStateRef stateFree = FreeMemAux(C, CE, State, 0, false, IsKnownToBeAllocated)) { - ProgramStateRef stateRealloc = MallocMemAux(C, CE, TotalSize, + ProgramStateRef stateRealloc = MallocMemAux(C, CE, Arg1, TotalSize, UnknownVal(), stateFree); if (!stateRealloc) return nullptr; @@ -2506,7 +2509,7 @@ SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); SVal TotalSize = evalMulForBufferSize(C, CE->getArg(0), CE->getArg(1)); - return MallocMemAux(C, CE, TotalSize, zeroVal, State); + return MallocMemAux(C, CE, CE->getArg(0), TotalSize, zeroVal, State); } MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N, Index: clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -69,6 +69,9 @@ ASTContext &Ctx) { // Get the base region, stripping away fields and elements. R = R->getBaseRegion(); + if (const SymbolicRegion *SR = R->getSymbolicBase()) + R = SR->getSuperRegion(); + SourceManager &SM = Ctx.getSourceManager(); SourceRange range; os << "Address of "; @@ -80,10 +83,10 @@ "declared on line " << SM.getExpansionLineNumber(CL->getBeginLoc()) << " returned to caller"; range = CL->getSourceRange(); - } else if (const auto *AR = dyn_cast(R)) { - const Expr *ARE = AR->getExpr(); - SourceLocation L = ARE->getBeginLoc(); - range = ARE->getSourceRange(); + } else if (const auto *MBR = dyn_cast(R)) { + const Expr *AllocExpr = MBR->getAllocExpr(); + SourceLocation L = AllocExpr->getBeginLoc(); + range = AllocExpr->getSourceRange(); os << "stack memory allocated by call to alloca() on line " << SM.getExpansionLineNumber(L); } else if (const auto *BR = dyn_cast(R)) { Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -2039,7 +2039,7 @@ if (const auto *SR = L->getRegionAs()) { if (SR->getSymbol()->getType()->getPointeeType()->isVoidType()) CanDereference = false; - } else if (L->getRegionAs()) + } else if (L->getRegionAs()) CanDereference = false; // At this point we are dealing with the region's LValue. Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -1210,7 +1210,7 @@ DynamicTypeInfo DTI = getDynamicTypeInfo(getState(), Receiver); if (!DTI.isValid()) { - assert(isa(Receiver) && + assert(isa(Receiver) && "Unhandled untyped region class!"); return {}; } Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -761,11 +761,20 @@ // heap. We realize this is an approximation that might not correctly model // a custom global allocator. if (symVal.isUnknown()) { - if (IsStandardGlobalOpNewFunction) - symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); - else + if (IsStandardGlobalOpNewFunction) { + DefinedOrUnknownSVal Size = UnknownVal(); + const Expr *SizeExpr = nullptr; + if (Optional TempSizeExpr = CNE->getArraySize()) { + SizeExpr = *TempSizeExpr; + Size = State->getSVal(SizeExpr, LCtx).castAs(); + } + + symVal = svalBuilder.getConjuredHeapSymbolVal( + CNE, CNE->getOperatorNew(), SizeExpr, Size, LCtx, blockCount); + } else { symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(), blockCount); + } } CallEventManager &CEMgr = getStateManager().getCallEventManager(); Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -654,15 +654,26 @@ // See if we need to conjure a heap pointer instead of // a regular unknown pointer. bool IsHeapPointer = false; - if (const auto *CNE = dyn_cast(E)) - if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { - // FIXME: Delegate this to evalCall in MallocChecker? - IsHeapPointer = true; + const auto *CNE = dyn_cast(E); + if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) { + // FIXME: Delegate this to evalCall in MallocChecker? + IsHeapPointer = true; + } + + DefinedOrUnknownSVal Size = UnknownVal(); + const Expr *SizeExpr = nullptr; + if (CNE) { + if (Optional TempSizeExpr = CNE->getArraySize()) { + SizeExpr = *TempSizeExpr; + Size = State->getSVal(SizeExpr, LCtx).castAs(); } + } - R = IsHeapPointer ? svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count) - : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, - Count); + R = IsHeapPointer + ? svalBuilder.getConjuredHeapSymbolVal( + E, CNE ? CNE->getOperatorNew() : nullptr, SizeExpr, Size, + LCtx, Count) + : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count); } return State->BindExpr(E, LCtx, R); } Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/MemRegion.cpp +++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -62,53 +62,16 @@ // MemRegion Construction. //===----------------------------------------------------------------------===// -template -RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, - const SuperTy *superRegion) { +template +RegionTy *MemRegionManager::getSubRegion(ArgsTy &&... Args) { llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, arg1, superRegion); + RegionTy::ProfileRegion(ID, std::forward(Args)...); void *InsertPos; auto *R = cast_or_null(Regions.FindNodeOrInsertPos(ID, InsertPos)); if (!R) { R = A.Allocate(); - new (R) RegionTy(arg1, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -template -RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, - const SuperTy *superRegion) { - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, arg1, arg2, superRegion); - void *InsertPos; - auto *R = cast_or_null(Regions.FindNodeOrInsertPos(ID, InsertPos)); - - if (!R) { - R = A.Allocate(); - new (R) RegionTy(arg1, arg2, superRegion); - Regions.InsertNode(R, InsertPos); - } - - return R; -} - -template -RegionTy* MemRegionManager::getSubRegion(const Arg1Ty arg1, const Arg2Ty arg2, - const Arg3Ty arg3, - const SuperTy *superRegion) { - llvm::FoldingSetNodeID ID; - RegionTy::ProfileRegion(ID, arg1, arg2, arg3, superRegion); - void *InsertPos; - auto *R = cast_or_null(Regions.FindNodeOrInsertPos(ID, InsertPos)); - - if (!R) { - R = A.Allocate(); - new (R) RegionTy(arg1, arg2, arg3, superRegion); + new (R) RegionTy(std::forward(Args)...); Regions.InsertNode(R, InsertPos); } @@ -196,10 +159,6 @@ return Extent; } -DefinedOrUnknownSVal AllocaRegion::getExtent(SValBuilder &svalBuilder) const { - return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); -} - DefinedOrUnknownSVal SymbolicRegion::getExtent(SValBuilder &svalBuilder) const { return nonloc::SymbolVal(svalBuilder.getSymbolManager().getExtentSymbol(this)); } @@ -262,17 +221,22 @@ ID.AddPointer(superRegion); } -void AllocaRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const Expr *Ex, unsigned cnt, - const MemRegion *superRegion) { - ID.AddInteger(static_cast(AllocaRegionKind)); - ID.AddPointer(Ex); - ID.AddInteger(cnt); +void MemoryBlockRegion::ProfileRegion( + llvm::FoldingSetNodeID &ID, const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, unsigned BlockCount, + const MemRegion *superRegion) { + ID.AddInteger(static_cast(MemoryBlockRegionKind)); + ID.AddPointer(AllocExpr); + ID.AddPointer(AllocDecl); + ID.AddPointer(SizeExpr); + ID.Add(Size); + ID.AddInteger(BlockCount); ID.AddPointer(superRegion); } -void AllocaRegion::Profile(llvm::FoldingSetNodeID& ID) const { - ProfileRegion(ID, Ex, Cnt, superRegion); +void MemoryBlockRegion::Profile(llvm::FoldingSetNodeID &ID) const { + ProfileRegion(ID, AllocExpr, AllocDecl, SizeExpr, Size, BlockCount, + superRegion); } void CompoundLiteralRegion::Profile(llvm::FoldingSetNodeID& ID) const { @@ -455,8 +419,21 @@ os << ""; } -void AllocaRegion::dumpToStream(raw_ostream &os) const { - os << "alloca{S" << Ex->getID(getContext()) << ',' << Cnt << '}'; +void MemoryBlockRegion::dumpToStream(raw_ostream &os) const { + os << "memory_block{"; + + if (AllocExpr) + os << 'S' << AllocExpr->getID(getContext()); + else + os << "no stmt"; + os << ','; + + if (AllocDecl) + os << 'D' << AllocDecl->getID(); + else + os << "no decl"; + + os << ',' << Size << ',' << BlockCount << '}'; } void FunctionCodeRegion::dumpToStream(raw_ostream &os) const { @@ -524,7 +501,7 @@ } void SymbolicRegion::dumpToStream(raw_ostream &os) const { - if (isa(getSuperRegion())) + if (isa(getSuperRegion()->getMemorySpace())) os << "Heap"; os << "SymRegion{" << sym << '}'; } @@ -848,7 +825,6 @@ const MemRegion *sReg = nullptr; if (D->hasGlobalStorage() && !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 @@ -889,11 +865,26 @@ sReg = getUnknownRegion(); } else { if (D->hasLocalStorage()) { - sReg = isa(D) || isa(D) - ? static_cast(getStackArgumentsRegion(STC)) - : static_cast(getStackLocalsRegion(STC)); - } - else { + const Expr *SizeExpr = nullptr; + if (D->getType()->isArrayType()) + if (const TypeSourceInfo *TSI = D->getTypeSourceInfo()) + if (const auto ATL = TSI->getTypeLoc().getAs()) + SizeExpr = ATL.getSizeExpr(); + + bool IsArgument = isa(D) || isa(D); + if (IsArgument) + sReg = getStackArgumentsRegion(STC); + else + sReg = getStackLocalsRegion(STC); + + if (SizeExpr) { + // Create a temporary 'VarRegion' to obtain the extent. + const VarRegion *TempVR = getSubRegion(D, sReg); + sReg = getStackMemoryBlockRegion(nullptr, D, SizeExpr, + TempVR->getExtent(SVB), STC, + STC->getBlockCount(), IsArgument); + } + } else { assert(D->isStaticLocal()); const Decl *STCD = STC->getDecl(); if (isa(STCD) || isa(STCD)) @@ -1028,6 +1019,31 @@ return getSubRegion(Sym, getHeapRegion()); } +const SymbolicRegion *MemRegionManager::getSymbolicHeapMemoryBlock( + SymbolRef Sym, const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, unsigned BlockCount) { + return getSubRegion( + Sym, getSubRegion(AllocExpr, AllocDecl, SizeExpr, Size, + BlockCount, getHeapRegion())); +} + +const MemoryBlockRegion *MemRegionManager::getStackMemoryBlockRegion( + const Expr *AllocExpr, const Decl *AllocDecl, const Expr *SizeExpr, + DefinedOrUnknownSVal Size, const LocationContext *LCtx, unsigned BlockCount, + bool IsArgument) { + const StackFrameContext *STC = LCtx->getStackFrame(); + assert(STC); + + const MemSpaceRegion *SuperR = nullptr; + if (IsArgument) + SuperR = getStackArgumentsRegion(STC); + else + SuperR = getStackLocalsRegion(STC); + + return getSubRegion(AllocExpr, AllocDecl, SizeExpr, Size, + BlockCount, SuperR); +} + const FieldRegion* MemRegionManager::getFieldRegion(const FieldDecl *d, const SubRegion* superRegion){ @@ -1117,14 +1133,6 @@ return getSubRegion(PT, getStackArgumentsRegion(STC)); } -const AllocaRegion* -MemRegionManager::getAllocaRegion(const Expr *E, unsigned cnt, - const LocationContext *LC) { - const StackFrameContext *STC = LC->getStackFrame(); - assert(STC); - return getSubRegion(E, cnt, getStackLocalsRegion(STC)); -} - const MemSpaceRegion *MemRegion::getMemorySpace() const { const MemRegion *R = this; const auto *SR = dyn_cast(this); @@ -1320,7 +1328,7 @@ goto Finish; case MemRegion::SymbolicRegionKind: - case MemRegion::AllocaRegionKind: + case MemRegion::MemoryBlockRegionKind: case MemRegion::CompoundLiteralRegionKind: case MemRegion::CXXThisRegionKind: case MemRegion::StringRegionKind: Index: clang/lib/StaticAnalyzer/Core/RegionStore.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1144,7 +1144,7 @@ if (Regions) Regions->push_back(baseR); - if (isa(baseR) || isa(baseR)) { + if (isa(baseR) || isa(baseR)) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelevant. DefinedOrUnknownSVal V = Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -187,18 +187,28 @@ return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal -SValBuilder::getConjuredHeapSymbolVal(const Expr *E, - const LocationContext *LCtx, - unsigned VisitCount) { - QualType T = E->getType(); - assert(Loc::isLocType(T)); - assert(SymbolManager::canSymbolicate(T)); - if (T->isNullPtrType()) - return makeZeroVal(T); +DefinedOrUnknownSVal SValBuilder::getConjuredHeapSymbolVal( + const Expr *AllocExpr, const Decl *AllocDecl, const Expr *SizeExpr, + DefinedOrUnknownSVal Size, const LocationContext *LCtx, + unsigned BlockCount) { + QualType Ty = AllocExpr->getType(); + assert(Loc::isLocType(Ty)); + assert(SymbolManager::canSymbolicate(Ty)); + if (Ty->isNullPtrType()) + return makeZeroVal(Ty); + + SymbolRef Sym = SymMgr.conjureSymbol(AllocExpr, LCtx, Ty, BlockCount); + return loc::MemRegionVal(MemMgr.getSymbolicHeapMemoryBlock( + Sym, AllocExpr, AllocDecl, SizeExpr, Size, BlockCount)); +} - SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount); - return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym)); +DefinedOrUnknownSVal +SValBuilder::getStackSymbolVal(const Expr *AllocExpr, const Decl *AllocDecl, + const Expr *SizeExpr, DefinedOrUnknownSVal Size, + const LocationContext *LCtx, unsigned BlockCount, + bool IsArgument) { + return loc::MemRegionVal(MemMgr.getStackMemoryBlockRegion( + AllocExpr, AllocDecl, SizeExpr, Size, LCtx, BlockCount, IsArgument)); } DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag, Index: clang/lib/StaticAnalyzer/Core/Store.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/Store.cpp +++ clang/lib/StaticAnalyzer/Core/Store.cpp @@ -129,7 +129,7 @@ case MemRegion::StringRegionKind: // FIXME: Need to handle arbitrary downcasts. case MemRegion::SymbolicRegionKind: - case MemRegion::AllocaRegionKind: + case MemRegion::MemoryBlockRegionKind: case MemRegion::CompoundLiteralRegionKind: case MemRegion::FieldRegionKind: case MemRegion::ObjCIvarRegionKind: @@ -502,7 +502,7 @@ // char *p = __builtin_alloc(10); // p[1] = 8; // - // Observe that 'p' binds to an AllocaRegion. + // Observe that 'p' binds to a 'MemoryBlockRegion'. return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset, BaseRegion, Ctx)); } Index: clang/lib/StaticAnalyzer/Core/SymbolManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ clang/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -442,9 +442,9 @@ // FIXME: This is a gross over-approximation. What we really need is a way to // tell if anything still refers to this region. Unlike SymbolicRegions, - // AllocaRegions don't have associated symbols, though, so we don't actually - // have a way to track their liveness. - if (isa(MR)) + // MemoryBlockRegions don't have associated symbols, though, so we don't + // actually have a way to track their liveness. + if (isa(MR)) return true; if (isa(MR)) Index: clang/test/Analysis/array-struct.c =================================================================== --- clang/test/Analysis/array-struct.c +++ clang/test/Analysis/array-struct.c @@ -53,7 +53,7 @@ g1(&data); } -// AllocaRegion test. +// MemoryBlockRegion test. void f6() { char *p; p = __builtin_alloca(10); Index: clang/test/Analysis/exercise-ps.c =================================================================== --- clang/test/Analysis/exercise-ps.c +++ clang/test/Analysis/exercise-ps.c @@ -22,7 +22,7 @@ // expected-note{{include the header or explicitly provide a declaration for 'memcpy'}} } -// AllocaRegion is untyped. Void pointer isn't of much help either. Before +// MemoryBlockRegion is untyped. Void pointer isn't of much help either. Before // realizing that the value is undefined, we need to somehow figure out // what type of value do we expect. void f3(void *dest) { Index: clang/test/Analysis/explain-svals.cpp =================================================================== --- clang/test/Analysis/explain-svals.cpp +++ clang/test/Analysis/explain-svals.cpp @@ -87,7 +87,7 @@ void test_5(int i) { clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}} clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}} - clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}} + clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to memory block region allocated by '__builtin_alloca\(i\)'$}}}} } }; } // end of anonymous namespace Index: clang/test/Analysis/pr22954.c =================================================================== --- clang/test/Analysis/pr22954.c +++ clang/test/Analysis/pr22954.c @@ -625,9 +625,8 @@ clang_analyzer_eval(m29[i].s3[2] == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(m29[i].s3[3] == 1); // expected-warning{{UNKNOWN}} clang_analyzer_eval(m29[j].s3[k] == 1); // expected-warning{{TRUE}} + // expected-warning@-1 {{Potential leak of memory pointed to by field 's4'}} clang_analyzer_eval(l29->s1[m] == 2); // expected-warning{{UNKNOWN}} - // FIXME: Should warn that m29[i].s4 leaks. But not on the previous line, - // because l29 and m29 alias. return 0; } Index: clang/www/analyzer/implicit_checks.html =================================================================== --- clang/www/analyzer/implicit_checks.html +++ clang/www/analyzer/implicit_checks.html @@ -84,10 +84,9 @@