@@ -346,10 +346,6 @@ namespace {
346
346
};
347
347
348
348
BUGTYPE_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" )
353
349
354
350
struct Leak : virtual public CheckerFrontend {
355
351
// Leaks should not be reported if they are post-dominated by a sink:
@@ -410,8 +406,7 @@ class MallocChecker
410
406
DynMemFrontend<DoubleFree, Leak, UseFree, BadFree, FreeAlloca, OffsetFree,
411
407
UseZeroAllocated>
412
408
MallocChecker;
413
- DynMemFrontend<DoubleFree, DoubleDelete, UseFree, BadFree, OffsetFree,
414
- UseZeroAllocated>
409
+ DynMemFrontend<DoubleFree, UseFree, BadFree, OffsetFree, UseZeroAllocated>
415
410
NewDeleteChecker;
416
411
DynMemFrontend<Leak> NewDeleteLeaksChecker;
417
412
DynMemFrontend<FreeAlloca, MismatchedDealloc> MismatchedDeallocatorChecker;
@@ -784,9 +779,6 @@ class MallocChecker
784
779
void checkUseZeroAllocated (SymbolRef Sym, CheckerContext &C,
785
780
const Stmt *S) const ;
786
781
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
-
790
782
// / Check if the function is known to free memory, or if it is
791
783
// / "interesting" and should be modeled explicitly.
792
784
// /
@@ -848,8 +840,6 @@ class MallocChecker
848
840
void HandleDoubleFree (CheckerContext &C, SourceRange Range, bool Released,
849
841
SymbolRef Sym, SymbolRef PrevSym) const ;
850
842
851
- void HandleDoubleDelete (CheckerContext &C, SymbolRef Sym) const ;
852
-
853
843
void HandleUseZeroAlloc (CheckerContext &C, SourceRange Range,
854
844
SymbolRef Sym) const ;
855
845
@@ -2737,7 +2727,8 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2737
2727
(Released ? " Attempt to free released memory"
2738
2728
: " Attempt to free non-owned memory" ),
2739
2729
N);
2740
- R->addRange (Range);
2730
+ if (Range.isValid ())
2731
+ R->addRange (Range);
2741
2732
R->markInteresting (Sym);
2742
2733
if (PrevSym)
2743
2734
R->markInteresting (PrevSym);
@@ -2746,26 +2737,6 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
2746
2737
}
2747
2738
}
2748
2739
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
-
2769
2740
void MallocChecker::HandleUseZeroAlloc (CheckerContext &C, SourceRange Range,
2770
2741
SymbolRef Sym) const {
2771
2742
const UseZeroAllocated *Frontend =
@@ -3136,10 +3107,22 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
3136
3107
return ;
3137
3108
}
3138
3109
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`.
3139
3117
if (const auto *DC = dyn_cast<CXXDestructorCall>(&Call)) {
3140
3118
SymbolRef Sym = DC->getCXXThisVal ().getAsSymbol ();
3141
- if (!Sym || checkDoubleDelete (Sym, C) )
3119
+ if (!Sym)
3142
3120
return ;
3121
+ if (isReleased (Sym, C)) {
3122
+ HandleDoubleFree (C, SourceRange (), /* Released=*/ true , Sym,
3123
+ /* PrevSym=*/ nullptr );
3124
+ return ;
3125
+ }
3143
3126
}
3144
3127
3145
3128
// We need to handle getline pre-conditions here before the pointed region
@@ -3321,15 +3304,6 @@ void MallocChecker::checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
3321
3304
}
3322
3305
}
3323
3306
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
-
3333
3307
// Check if the location is a freed symbolic region.
3334
3308
void MallocChecker::checkLocation (SVal l, bool isLoad, const Stmt *S,
3335
3309
CheckerContext &C) const {
0 commit comments