diff options
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index e06662b16934..f7c4ea10c438 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -26,7 +26,6 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" -#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -288,6 +287,9 @@ private: ProgramStateRef State, AllocationFamily Family = AF_Malloc); + static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE, + ProgramStateRef State); + // Check if this malloc() for special flags. At present that means M_ZERO or // __GFP_ZERO (in which case, treat it like calloc). llvm::Optional<ProgramStateRef> @@ -776,6 +778,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State); } } else if (FunI == II_kmalloc) { + if (CE->getNumArgs() < 1) + return; llvm::Optional<ProgramStateRef> MaybeState = performKernelMalloc(CE, C, State); if (MaybeState.hasValue()) @@ -805,6 +809,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } else if (FunI == II_strndup) { State = MallocUpdateRefState(C, CE, State); } else if (FunI == II_alloca || FunI == II_win_alloca) { + if (CE->getNumArgs() < 1) + return; State = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(), State, AF_Alloca); State = ProcessZeroAllocation(C, CE, 0, State); @@ -982,10 +988,58 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE, // existing binding. State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray : AF_CXXNew); + State = addExtentSize(C, NE, State); State = ProcessZeroAllocation(C, NE, 0, State); C.addTransition(State); } +// Sets the extent value of the MemRegion allocated by +// new expression NE to its size in Bytes. +// +ProgramStateRef MallocChecker::addExtentSize(CheckerContext &C, + const CXXNewExpr *NE, + ProgramStateRef State) { + if (!State) + return nullptr; + SValBuilder &svalBuilder = C.getSValBuilder(); + SVal ElementCount; + const LocationContext *LCtx = C.getLocationContext(); + const SubRegion *Region; + if (NE->isArray()) { + const Expr *SizeExpr = NE->getArraySize(); + ElementCount = State->getSVal(SizeExpr, C.getLocationContext()); + // Store the extent size for the (symbolic)region + // containing the elements. + Region = (State->getSVal(NE, LCtx)) + .getAsRegion() + ->getAs<SubRegion>() + ->getSuperRegion() + ->getAs<SubRegion>(); + } else { + ElementCount = svalBuilder.makeIntVal(1, true); + Region = (State->getSVal(NE, LCtx)).getAsRegion()->getAs<SubRegion>(); + } + assert(Region); + + // Set the region's extent equal to the Size in Bytes. + QualType ElementType = NE->getAllocatedType(); + ASTContext &AstContext = C.getASTContext(); + CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType); + + if (ElementCount.getAs<NonLoc>()) { + DefinedOrUnknownSVal Extent = Region->getExtent(svalBuilder); + // size in Bytes = ElementCount*TypeSize + SVal SizeInBytes = svalBuilder.evalBinOpNN( + State, BO_Mul, ElementCount.castAs<NonLoc>(), + svalBuilder.makeArrayIndex(TypeSize.getQuantity()), + svalBuilder.getArrayIndexType()); + DefinedOrUnknownSVal extentMatchesSize = svalBuilder.evalEQ( + State, Extent, SizeInBytes.castAs<DefinedOrUnknownSVal>()); + State = State->assume(extentMatchesSize, true); + } + return State; +} + void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const { @@ -2095,12 +2149,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, const MemRegion *Region = nullptr; std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); - ProgramPoint P = AllocNode->getLocation(); - const Stmt *AllocationStmt = nullptr; - if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) - AllocationStmt = Exit->getCalleeContext()->getCallSite(); - else if (Optional<StmtPoint> SP = P.getAs<StmtPoint>()) - AllocationStmt = SP->getStmt(); + const Stmt *AllocationStmt = PathDiagnosticLocation::getStmt(AllocNode); if (AllocationStmt) LocUsedForUniqueing = PathDiagnosticLocation::createBegin(AllocationStmt, C.getSourceManager(), @@ -2529,6 +2578,11 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly( return true; } + if (FName == "connectImpl" && + FD->getQualifiedNameAsString() == "QObject::connectImpl") { + return true; + } + // Handle cases where we know a buffer's /address/ can escape. // Note that the above checks handle some special cases where we know that // even though the address escapes, it's still our responsibility to free the @@ -2627,22 +2681,7 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, if (!RS) return nullptr; - const Stmt *S = nullptr; - const char *Msg = nullptr; - StackHintGeneratorForSymbol *StackHint = nullptr; - - // Retrieve the associated statement. - ProgramPoint ProgLoc = N->getLocation(); - if (Optional<StmtPoint> SP = ProgLoc.getAs<StmtPoint>()) { - S = SP->getStmt(); - } else if (Optional<CallExitEnd> Exit = ProgLoc.getAs<CallExitEnd>()) { - S = Exit->getCalleeContext()->getCallSite(); - } else if (Optional<BlockEdge> Edge = ProgLoc.getAs<BlockEdge>()) { - // If an assumption was made on a branch, it should be caught - // here by looking at the state transition. - S = Edge->getSrc()->getTerminator(); - } - + const Stmt *S = PathDiagnosticLocation::getStmt(N); if (!S) return nullptr; @@ -2650,6 +2689,8 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, // (__attribute__((cleanup))). // Find out if this is an interesting point and what is the kind. + const char *Msg = nullptr; + StackHintGeneratorForSymbol *StackHint = nullptr; if (Mode == Normal) { if (isAllocated(RS, RSPrev, S)) { Msg = "Memory is allocated"; |