diff options
author | Jordan Rose <jordan_rose@apple.com> | 2014-01-08 18:46:55 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2014-01-08 18:46:55 +0000 |
commit | 656fdd55dd0dffb9177b8008fe030c24300507cb (patch) | |
tree | 70fcd75b358ce31567b4ef5b5429d34b1cd5fa73 /clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | |
parent | df1e1960ac8168d6970f1fbf669c2005b0537372 (diff) | |
download | bcm5719-llvm-656fdd55dd0dffb9177b8008fe030c24300507cb.tar.gz bcm5719-llvm-656fdd55dd0dffb9177b8008fe030c24300507cb.zip |
[analyzer] Warn about double-delete in C++ at the second delete...
...rather somewhere in the destructor when we try to access something and
realize the object has already been deleted. This is necessary because
the destructor is processed before the 'delete' itself.
Patch by Karthik Bhat!
llvm-svn: 198779
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp | 44 |
1 files changed, 42 insertions, 2 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 87d7e89e52e..92297ca3886 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -155,6 +155,7 @@ class MallocChecker : public Checker<check::DeadSymbols, eval::Assume> { mutable OwningPtr<BugType> BT_DoubleFree; + mutable OwningPtr<BugType> BT_DoubleDelete; mutable OwningPtr<BugType> BT_Leak; mutable OwningPtr<BugType> BT_UseFree; mutable OwningPtr<BugType> BT_BadFree; @@ -277,6 +278,8 @@ private: bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; + bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const; + /// Check if the function is known free memory, or if it is /// "interesting" and should be modeled explicitly. /// @@ -320,6 +323,8 @@ private: void ReportDoubleFree(CheckerContext &C, SourceRange Range, bool Released, SymbolRef Sym, SymbolRef PrevSym) const; + void ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const; + /// Find the location of the allocation for Sym on the path leading to the /// exploded node N. LeakInfo getAllocationSite(const ExplodedNode *N, SymbolRef Sym, @@ -1413,6 +1418,27 @@ void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, } } +void MallocChecker::ReportDoubleDelete(CheckerContext &C, SymbolRef Sym) const { + + if (!Filter.CNewDeleteChecker) + return; + + if (!isTrackedByCurrentChecker(C, Sym)) + return; + + if (ExplodedNode *N = C.generateSink()) { + if (!BT_DoubleDelete) + BT_DoubleDelete.reset(new BugType("Double delete", "Memory Error")); + + BugReport *R = new BugReport(*BT_DoubleDelete, + "Attempt to delete released memory", N); + + R->markInteresting(Sym); + R->addVisitor(new MallocBugVisitor(Sym)); + C.emitReport(R); + } +} + ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE, bool FreesOnFail) const { @@ -1693,6 +1719,12 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, void MallocChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { + if (const CXXDestructorCall *DC = dyn_cast<CXXDestructorCall>(&Call)) { + SymbolRef Sym = DC->getCXXThisVal().getAsSymbol(); + if (!Sym || checkDoubleDelete(Sym, C)) + return; + } + // We will check for double free in the post visit. if (const AnyFunctionCall *FC = dyn_cast<AnyFunctionCall>(&Call)) { const FunctionDecl *FD = FC->getDecl(); @@ -1801,8 +1833,7 @@ bool MallocChecker::isReleased(SymbolRef Sym, CheckerContext &C) const { bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const { - // FIXME: Handle destructor called from delete more precisely. - if (isReleased(Sym, C) && S) { + if (isReleased(Sym, C)) { ReportUseAfterFree(C, S->getSourceRange(), Sym); return true; } @@ -1810,6 +1841,15 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, return false; } +bool MallocChecker::checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const { + + if (isReleased(Sym, C)) { + ReportDoubleDelete(C, Sym); + return true; + } + return false; +} + // Check if the location is a freed symbolic region. void MallocChecker::checkLocation(SVal l, bool isLoad, const Stmt *S, CheckerContext &C) const { |