From: Anna Zaks Date: Thu, 16 Feb 2012 22:26:07 +0000 (+0000) Subject: [analyzer] Malloc Checker: Make the diagnostic visitor handle the case X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe571608b925079227d053a459eca86f7408e5c6;p=clang [analyzer] Malloc Checker: Make the diagnostic visitor handle the case of failing realloc. + Minor cleanups. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150732 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a14057980f..044db28400 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -184,11 +184,18 @@ private: /// region. class MallocBugVisitor : public BugReporterVisitor { protected: + enum NotificationMode { + Normal, + Complete, + ReallocationFailed + }; + // The allocated region symbol tracked by the main analysis. SymbolRef Sym; + NotificationMode Mode; public: - MallocBugVisitor(SymbolRef S) : Sym(S) {} + MallocBugVisitor(SymbolRef S) : Sym(S), Mode(Normal) {} virtual ~MallocBugVisitor() {} void Profile(llvm::FoldingSetNodeID &ID) const { @@ -197,14 +204,28 @@ private: ID.AddPointer(Sym); } - inline bool isAllocated(const RefState *S, const RefState *SPrev) { + inline bool isAllocated(const RefState *S, const RefState *SPrev, + const Stmt *Stmt) { // Did not track -> allocated. Other state (released) -> allocated. - return ((S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated())); + return (Stmt && isa(Stmt) && + (S && S->isAllocated()) && (!SPrev || !SPrev->isAllocated())); } - inline bool isReleased(const RefState *S, const RefState *SPrev) { + inline bool isReleased(const RefState *S, const RefState *SPrev, + const Stmt *Stmt) { // Did not track -> released. Other state (allocated) -> released. - return ((S && S->isReleased()) && (!SPrev || !SPrev->isReleased())); + return (Stmt && isa(Stmt) && + (S && S->isReleased()) && (!SPrev || !SPrev->isReleased())); + } + + inline bool isReallocFailedCheck(const RefState *S, const RefState *SPrev, + const Stmt *Stmt) { + // If the expression is not a call, and the state change is + // released -> allocated, it must be the realloc return value + // check. If we have to handle more cases here, it might be cleaner just + // to track this extra bit in the state itself. + return ((!Stmt || !isa(Stmt)) && + (S && S->isAllocated()) && (SPrev && !SPrev->isAllocated())); } PathDiagnosticPiece *VisitNode(const ExplodedNode *N, @@ -502,6 +523,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, "Try to free a memory block that has been released")); BugReport *R = new BugReport(*BT_DoubleFree, BT_DoubleFree->getDescription(), N); + R->addRange(ArgExpr->getSourceRange()); R->addVisitor(new MallocBugVisitor(Sym)); C.EmitReport(R); } @@ -861,11 +883,11 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { return; // Check if we are returning freed memory. - if (checkUseAfterFree(Sym, C, S)) + if (checkUseAfterFree(Sym, C, E)) return; // Check if the symbol is escaping. - checkEscape(Sym, S, C); + checkEscape(Sym, E, C); } bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, @@ -1051,28 +1073,58 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N, if (!RS && !RSPrev) return 0; - // We expect the interesting locations be StmtPoints corresponding to call - // expressions. We do not support indirect function calls as of now. - const CallExpr *CE = 0; - if (isa(N->getLocation())) - CE = dyn_cast(cast(N->getLocation()).getStmt()); - if (!CE) - return 0; - const FunctionDecl *funDecl = CE->getDirectCallee(); - if (!funDecl) + const Stmt *S = 0; + const char *Msg = 0; + + // Retrieve the associated statement. + ProgramPoint ProgLoc = N->getLocation(); + if (isa(ProgLoc)) + S = cast(ProgLoc).getStmt(); + // If an assumption was made on a branch, it should be caught + // here by looking at the state transition. + if (isa(ProgLoc)) { + const CFGBlock *srcBlk = cast(ProgLoc).getSrc(); + S = srcBlk->getTerminator(); + } + if (!S) return 0; // Find out if this is an interesting point and what is the kind. - const char *Msg = 0; - if (isAllocated(RS, RSPrev)) - Msg = "Memory is allocated here"; - else if (isReleased(RS, RSPrev)) - Msg = "Memory is released here"; + if (Mode == Normal) { + if (isAllocated(RS, RSPrev, S)) + Msg = "Memory is allocated"; + else if (isReleased(RS, RSPrev, S)) + Msg = "Memory is released"; + else if (isReallocFailedCheck(RS, RSPrev, S)) { + Mode = ReallocationFailed; + Msg = "Reallocation failed"; + } + + // We are in a special mode if a reallocation failed later in the path. + } else if (Mode == ReallocationFailed) { + // Generate a special diagnostic for the first realloc we find. + if (!isAllocated(RS, RSPrev, S) && !isReleased(RS, RSPrev, S)) + return 0; + + // Check that the name of the function is realloc. + const CallExpr *CE = dyn_cast(S); + if (!CE) + return 0; + const FunctionDecl *funDecl = CE->getDirectCallee(); + if (!funDecl) + return 0; + StringRef FunName = funDecl->getName(); + if (!(FunName.equals("realloc") || FunName.equals("reallocf"))) + return 0; + Msg = "Attempt to reallocate memory"; + Mode = Normal; + } + if (!Msg) return 0; // Generate the extra diagnostic. - PathDiagnosticLocation Pos(CE, BRC.getSourceManager(), + PathDiagnosticLocation Pos(S, BRC.getSourceManager(), N->getLocationContext()); return new PathDiagnosticEventPiece(Pos, Msg); } diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c index 8727bc26c6..2539a28e8b 100644 --- a/test/Analysis/malloc-plist.c +++ b/test/Analysis/malloc-plist.c @@ -2,6 +2,8 @@ typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); +void free(void *); +void *realloc(void *ptr, size_t size); void diagnosticTest(int in) { if (in > 5) { @@ -17,12 +19,24 @@ void myArrayAllocation() { A[0] = 0;// expected-warning {{leak}} } +void reallocDiagnostics() { + char * buf = malloc(100); + char * tmp; + tmp = (char*)realloc(buf, 0x1000000); + if (!tmp) { + return;// expected-warning {{leak}} + } + buf = tmp; + free(buf); +} + // CHECK: // CHECK: // CHECK: // CHECK: // CHECK: files // CHECK: +// CHECK: /Users/zaks/workspace/llvmgit/llvm/tools/clang/test/Analysis/malloc-plist.c // CHECK: // CHECK: diagnostics // CHECK: @@ -37,12 +51,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col5 // CHECK: file0 // CHECK: @@ -50,12 +64,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: @@ -67,7 +81,7 @@ void myArrayAllocation() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: @@ -75,12 +89,12 @@ void myArrayAllocation() { // CHECK: // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col14 // CHECK: file0 // CHECK: @@ -99,12 +113,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line7 +// CHECK: line9 // CHECK: col9 // CHECK: file0 // CHECK: @@ -112,12 +126,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: @@ -133,12 +147,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col9 // CHECK: file0 // CHECK: @@ -146,12 +160,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col27 // CHECK: file0 // CHECK: @@ -163,7 +177,7 @@ void myArrayAllocation() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col18 // CHECK: file0 // CHECK: @@ -171,21 +185,21 @@ void myArrayAllocation() { // CHECK: // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col27 // CHECK: file0 // CHECK: // CHECK: // CHECK: // CHECK: extended_message -// CHECK: Memory is allocated here +// CHECK: Memory is allocated // CHECK: message -// CHECK: Memory is allocated here +// CHECK: Memory is allocated // CHECK: // CHECK: // CHECK: kindcontrol @@ -195,12 +209,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col18 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line8 +// CHECK: line10 // CHECK: col27 // CHECK: file0 // CHECK: @@ -208,12 +222,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col6 // CHECK: file0 // CHECK: @@ -225,7 +239,7 @@ void myArrayAllocation() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col5 // CHECK: file0 // CHECK: @@ -233,12 +247,12 @@ void myArrayAllocation() { // CHECK: // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col6 // CHECK: file0 // CHECK: @@ -255,7 +269,7 @@ void myArrayAllocation() { // CHECK: typeMemory leak // CHECK: location // CHECK: -// CHECK: line11 +// CHECK: line13 // CHECK: col5 // CHECK: file0 // CHECK: @@ -271,12 +285,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line15 +// CHECK: line17 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line15 +// CHECK: line17 // CHECK: col5 // CHECK: file0 // CHECK: @@ -284,12 +298,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: @@ -305,12 +319,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col5 // CHECK: file0 // CHECK: @@ -318,12 +332,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col30 // CHECK: file0 // CHECK: @@ -335,7 +349,7 @@ void myArrayAllocation() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col9 // CHECK: file0 // CHECK: @@ -343,21 +357,21 @@ void myArrayAllocation() { // CHECK: // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col30 // CHECK: file0 // CHECK: // CHECK: // CHECK: // CHECK: extended_message -// CHECK: Memory is allocated here +// CHECK: Memory is allocated // CHECK: message -// CHECK: Memory is allocated here +// CHECK: Memory is allocated // CHECK: // CHECK: // CHECK: kindcontrol @@ -367,12 +381,12 @@ void myArrayAllocation() { // CHECK: start // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col9 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line16 +// CHECK: line18 // CHECK: col30 // CHECK: file0 // CHECK: @@ -380,12 +394,12 @@ void myArrayAllocation() { // CHECK: end // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line20 // CHECK: col1 // CHECK: file0 // CHECK: // CHECK: -// CHECK: line18 +// CHECK: line20 // CHECK: col1 // CHECK: file0 // CHECK: @@ -397,7 +411,7 @@ void myArrayAllocation() { // CHECK: kindevent // CHECK: location // CHECK: -// CHECK: line18 +// CHECK: line20 // CHECK: col1 // CHECK: file0 // CHECK: @@ -412,11 +426,369 @@ void myArrayAllocation() { // CHECK: typeMemory leak // CHECK: location // CHECK: -// CHECK: line18 +// CHECK: line20 // CHECK: col1 // CHECK: file0 // CHECK: // CHECK: +// CHECK: +// CHECK: path +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col28 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line23 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col28 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Memory is allocated +// CHECK: message +// CHECK: Memory is allocated +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line23 +// CHECK: col28 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col40 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line25 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col40 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Attempt to reallocate memory +// CHECK: message +// CHECK: Attempt to reallocate memory +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col18 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line25 +// CHECK: col40 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line26 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Reallocation failed +// CHECK: message +// CHECK: Reallocation failed +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col5 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col6 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line26 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Assuming 'tmp' is null +// CHECK: message +// CHECK: Assuming 'tmp' is null +// CHECK: +// CHECK: +// CHECK: kindcontrol +// CHECK: edges +// CHECK: +// CHECK: +// CHECK: start +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line26 +// CHECK: col12 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: end +// CHECK: +// CHECK: +// CHECK: line27 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line27 +// CHECK: col14 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: +// CHECK: kindevent +// CHECK: location +// CHECK: +// CHECK: line27 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: ranges +// CHECK: +// CHECK: +// CHECK: +// CHECK: line27 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: line27 +// CHECK: col14 +// CHECK: file0 +// CHECK: +// CHECK: +// CHECK: +// CHECK: extended_message +// CHECK: Allocated memory never released. Potential memory leak +// CHECK: message +// CHECK: Allocated memory never released. Potential memory leak +// CHECK: +// CHECK: +// CHECK: descriptionAllocated memory never released. Potential memory leak +// CHECK: categoryLogic error +// CHECK: typeMemory leak +// CHECK: location +// CHECK: +// CHECK: line27 +// CHECK: col9 +// CHECK: file0 +// CHECK: +// CHECK: // CHECK: // CHECK: // CHECK: