@@ -346,10 +346,6 @@ namespace {
346346 };
347347
348348BUGTYPE_PROVIDER (DoubleFree, " Double free" )
349- // TODO: Remove DoubleDelete as a separate bug type and when it would be
350- // emitted, emit DoubleFree reports instead. (Note that DoubleFree is already
351- // used for all allocation families, not just malloc/free.)
352- BUGTYPE_PROVIDER (DoubleDelete, " Double delete" )
353349
354350struct Leak : virtual public CheckerFrontend {
355351 // Leaks should not be reported if they are post-dominated by a sink:
@@ -410,8 +406,7 @@ class MallocChecker
410406 DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
411407 UseZeroAllocated>
412408 MallocChecker;
413- DynMemFrontend<DoubleFree, DoubleDelete, UseFree, BadFree, OffsetFree,
414- UseZeroAllocated>
409+ DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
415410 NewDeleteChecker;
416411 DynMemFrontend<Leak> NewDeleteLeaksChecker;
417412 DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
@@ -784,9 +779,6 @@ class MallocChecker
784779 void checkUseZeroAllocated (SymbolRef Sym, CheckerContext &C,
785780 const Stmt *S) const ;
786781
787- // / If in \p S \p Sym is being freed, check whether \p Sym was already freed.
788- bool checkDoubleDelete (SymbolRef Sym, CheckerContext &C) const ;
789-
790782 // / Check if the function is known to free memory, or if it is
791783 // / "interesting" and should be modeled explicitly.
792784 // /
@@ -848,8 +840,6 @@ class MallocChecker
848840 void HandleDoubleFree (CheckerContext &C, SourceRange Range, bool Released,
849841 SymbolRef Sym, SymbolRef PrevSym) const ;
850842
851- void HandleDoubleDelete (CheckerContext &C, SymbolRef Sym) const ;
852-
853843 void HandleUseZeroAlloc (CheckerContext &C, SourceRange Range,
854844 SymbolRef Sym) const ;
855845
@@ -2737,7 +2727,8 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
27372727 (Released ? " Attempt to free released memory"
27382728 : " Attempt to free non-owned memory" ),
27392729 N);
2740- R->addRange (Range);
2730+ if (Range.isValid ())
2731+ R->addRange (Range);
27412732 R->markInteresting (Sym);
27422733 if (PrevSym)
27432734 R->markInteresting (PrevSym);
@@ -2746,26 +2737,6 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
27462737 }
27472738}
27482739
2749- void MallocChecker::HandleDoubleDelete (CheckerContext &C, SymbolRef Sym) const {
2750- const DoubleDelete *Frontend = getRelevantFrontendAs<DoubleDelete>(C, Sym);
2751- if (!Frontend)
2752- return ;
2753- if (!Frontend->isEnabled ()) {
2754- C.addSink ();
2755- return ;
2756- }
2757-
2758- if (ExplodedNode *N = C.generateErrorNode ()) {
2759-
2760- auto R = std::make_unique<PathSensitiveBugReport>(
2761- Frontend->DoubleDeleteBug , " Attempt to delete released memory" , N);
2762-
2763- R->markInteresting (Sym);
2764- R->addVisitor <MallocBugVisitor>(Sym);
2765- C.emitReport (std::move (R));
2766- }
2767- }
2768-
27692740void MallocChecker::HandleUseZeroAlloc (CheckerContext &C, SourceRange Range,
27702741 SymbolRef Sym) const {
27712742 const UseZeroAllocated *Frontend =
@@ -3136,10 +3107,22 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
31363107 return ;
31373108 }
31383109
3110+ // If we see a `CXXDestructorCall` (that is, an _implicit_ destructor call)
3111+ // to a region that's symbolic and known to be already freed, then it must be
3112+ // implicitly triggered by a `delete` expression. In this situation we should
3113+ // emit a `DoubleFree` report _now_ (before entering the call to the
3114+ // destructor) because otherwise the destructor call can trigger a
3115+ // use-after-free bug (by accessing any member variable) and that would be
3116+ // (technically valid, but) less user-friendly report than the `DoubleFree`.
31393117 if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
31403118 SymbolRef Sym = DC->getCXXThisVal ().getAsSymbol ();
3141- if (!Sym || checkDoubleDelete (Sym, C) )
3119+ if (!Sym)
31423120 return ;
3121+ if (isReleased (Sym, C)) {
3122+ HandleDoubleFree (C, SourceRange (), /* Released=*/ true , Sym,
3123+ /* PrevSym=*/ nullptr );
3124+ return ;
3125+ }
31433126 }
31443127
31453128 // We need to handle getline pre-conditions here before the pointed region
@@ -3321,15 +3304,6 @@ void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
33213304 }
33223305}
33233306
3324- bool MallocChecker::checkDoubleDelete (SymbolRef Sym, CheckerContext &C) const {
3325-
3326- if (isReleased (Sym, C)) {
3327- HandleDoubleDelete (C, Sym);
3328- return true ;
3329- }
3330- return false ;
3331- }
3332-
33333307// Check if the location is a freed symbolic region.
33343308void MallocChecker::checkLocation (SVal l, bool isLoad, const Stmt *S,
33353309 CheckerContext &C) const {
0 commit comments