5252#include " clang/AST/DeclTemplate.h"
5353#include " clang/AST/Expr.h"
5454#include " clang/AST/ExprCXX.h"
55- #include " clang/AST/Type.h"
5655#include " clang/AST/TemplateBase.h"
57-
56+ # include " clang/AST/Type.h "
5857
5958#include " clang/AST/ParentMap.h"
6059#include " clang/ASTMatchers/ASTMatchFinder.h"
@@ -1102,19 +1101,22 @@ class StopTrackingCallback final : public SymbolVisitor {
11021101 }
11031102};
11041103
1105- // / EscapeTrackedCallback - A SymbolVisitor that marks allocated symbols as escaped.
1104+ // / EscapeTrackedCallback - A SymbolVisitor that marks allocated symbols as
1105+ // / escaped.
11061106// /
1107- // / This visitor is used to suppress false positive leak reports when smart pointers
1108- // / are nested in temporary objects passed by value to functions. When the analyzer
1109- // / can't see the destructor calls for temporary objects, it may incorrectly report
1110- // / leaks for memory that will be properly freed by the smart pointer destructors.
1107+ // / This visitor is used to suppress false positive leak reports when smart
1108+ // / pointers are nested in temporary objects passed by value to functions. When
1109+ // / the analyzer can't see the destructor calls for temporary objects, it may
1110+ // / incorrectly report leaks for memory that will be properly freed by the smart
1111+ // / pointer destructors.
11111112// /
11121113// / The visitor traverses reachable symbols from a given set of memory regions
11131114// / (typically smart pointer field regions) and marks any allocated symbols as
11141115// / escaped. Escaped symbols are not reported as leaks by checkDeadSymbols.
11151116// /
11161117// / Usage:
1117- // / auto Scan = State->scanReachableSymbols<EscapeTrackedCallback>(RootRegions);
1118+ // / auto Scan =
1119+ // / State->scanReachableSymbols<EscapeTrackedCallback>(RootRegions);
11181120// / ProgramStateRef NewState = Scan.getState();
11191121// / if (NewState != State) C.addTransition(NewState);
11201122class EscapeTrackedCallback final : public SymbolVisitor {
@@ -3123,24 +3125,27 @@ static bool isInStdNamespace(const DeclContext *DC) {
31233125// Start with unique_ptr and shared_ptr. (intentionally exclude weak_ptr)
31243126static bool isSmartOwningPtrType (QualType QT) {
31253127 QT = canonicalStrip (QT);
3126-
3128+
31273129 // First try TemplateSpecializationType (for std smart pointers)
31283130 const auto *TST = QT->getAs <TemplateSpecializationType>();
31293131 if (TST) {
31303132 const TemplateDecl *TD = TST->getTemplateName ().getAsTemplateDecl ();
3131- if (!TD) return false ;
3132-
3133+ if (!TD)
3134+ return false ;
3135+
31333136 const auto *ND = dyn_cast_or_null<NamedDecl>(TD->getTemplatedDecl ());
3134- if (!ND) return false ;
3135-
3137+ if (!ND)
3138+ return false ;
3139+
31363140 // Check if it's in std namespace
31373141 const DeclContext *DC = ND->getDeclContext ();
3138- if (!isInStdNamespace (DC)) return false ;
3139-
3142+ if (!isInStdNamespace (DC))
3143+ return false ;
3144+
31403145 StringRef Name = ND->getName ();
31413146 return Name == " unique_ptr" || Name == " shared_ptr" ;
31423147 }
3143-
3148+
31443149 // Also try RecordType (for custom smart pointer implementations)
31453150 const auto *RT = QT->getAs <RecordType>();
31463151 if (RT) {
@@ -3153,17 +3158,18 @@ static bool isSmartOwningPtrType(QualType QT) {
31533158 }
31543159 }
31553160 }
3156-
3161+
31573162 return false ;
31583163}
31593164
3160- static void collectDirectSmartOwningPtrFieldRegions (const MemRegion *Base,
3161- QualType RecQT,
3162- CheckerContext &C,
3163- SmallVectorImpl< const MemRegion*> &Out) {
3164- if (!Base) return ;
3165+ static void collectDirectSmartOwningPtrFieldRegions (
3166+ const MemRegion *Base, QualType RecQT, CheckerContext &C ,
3167+ SmallVectorImpl< const MemRegion *> &Out) {
3168+ if (!Base)
3169+ return ;
31653170 const auto *CRD = RecQT->getAsCXXRecordDecl ();
3166- if (!CRD) return ;
3171+ if (!CRD)
3172+ return ;
31673173
31683174 for (const FieldDecl *FD : CRD->fields ()) {
31693175 if (!isSmartOwningPtrType (FD->getType ()))
@@ -3181,44 +3187,47 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
31813187 (*PostFN)(this , C.getState (), Call, C);
31823188 }
31833189
3184- SmallVector<const MemRegion*, 8 > SmartPtrFieldRoots;
3185-
3186-
3190+ SmallVector<const MemRegion *, 8 > SmartPtrFieldRoots;
31873191
31883192 for (unsigned I = 0 , E = Call.getNumArgs (); I != E; ++I) {
31893193 const Expr *AE = Call.getArgExpr (I);
3190- if (!AE) continue ;
3194+ if (!AE)
3195+ continue ;
31913196 AE = AE->IgnoreParenImpCasts ();
31923197
31933198 QualType T = AE->getType ();
31943199
3195- // **Relaxation 1**: accept *any rvalue* by-value record (not only strict PRVALUE).
3196- if (AE->isGLValue ()) continue ;
3200+ // **Relaxation 1**: accept *any rvalue* by-value record (not only strict
3201+ // PRVALUE).
3202+ if (AE->isGLValue ())
3203+ continue ;
31973204
31983205 // By-value record only (no refs).
3199- if (!T->isRecordType () || T->isReferenceType ()) continue ;
3206+ if (!T->isRecordType () || T->isReferenceType ())
3207+ continue ;
32003208
32013209 // **Relaxation 2**: accept common temp/construct forms but don't overfit.
32023210 const bool LooksLikeTemp =
3203- isa<CXXTemporaryObjectExpr>(AE) ||
3204- isa<MaterializeTemporaryExpr>(AE) ||
3205- isa<CXXConstructExpr>(AE) ||
3206- isa<InitListExpr>(AE) ||
3207- isa<ImplicitCastExpr>(AE) || // handle common rvalue materializations
3211+ isa<CXXTemporaryObjectExpr>(AE) || isa<MaterializeTemporaryExpr>(AE) ||
3212+ isa<CXXConstructExpr>(AE) || isa<InitListExpr>(AE) ||
3213+ isa<ImplicitCastExpr>(AE) || // handle common rvalue materializations
32083214 isa<CXXBindTemporaryExpr>(AE); // handle CXXBindTemporaryExpr
3209- if (!LooksLikeTemp) continue ;
3215+ if (!LooksLikeTemp)
3216+ continue ;
32103217
32113218 // Require at least one direct smart owning pointer field by type.
32123219 const auto *CRD = T->getAsCXXRecordDecl ();
3213- if (!CRD) continue ;
3220+ if (!CRD)
3221+ continue ;
32143222 bool HasSmartPtrField = false ;
32153223 for (const FieldDecl *FD : CRD->fields ()) {
3216- if (isSmartOwningPtrType (FD->getType ())) {
3217- HasSmartPtrField = true ;
3218- break ;
3224+ if (isSmartOwningPtrType (FD->getType ())) {
3225+ HasSmartPtrField = true ;
3226+ break ;
32193227 }
32203228 }
3221- if (!HasSmartPtrField) continue ;
3229+ if (!HasSmartPtrField)
3230+ continue ;
32223231
32233232 // Find a region for the argument.
32243233 SVal VCall = Call.getArgSVal (I);
@@ -3227,20 +3236,21 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
32273236 const MemRegion *RExpr = VExpr.getAsRegion ();
32283237
32293238 const MemRegion *Base = RCall ? RCall : RExpr;
3230- if (!Base) {
3231- // Fallback: if we have a by-value record with unique_ptr fields but no region,
3232- // mark all allocated symbols as escaped
3239+ if (!Base) {
3240+ // Fallback: if we have a by-value record with unique_ptr fields but no
3241+ // region, mark all allocated symbols as escaped
32333242 ProgramStateRef State = C.getState ();
32343243 RegionStateTy RS = State->get <RegionState>();
32353244 ProgramStateRef NewState = State;
32363245 for (auto [Sym, RefSt] : RS) {
32373246 if (RefSt.isAllocated () || RefSt.isAllocatedOfSizeZero ()) {
3238- NewState = NewState->set <RegionState>(Sym, RefState::getEscaped (&RefSt));
3247+ NewState =
3248+ NewState->set <RegionState>(Sym, RefState::getEscaped (&RefSt));
32393249 }
32403250 }
32413251 if (NewState != State)
32423252 C.addTransition (NewState);
3243- continue ;
3253+ continue ;
32443254 }
32453255
32463256 // Push direct smart owning pointer field regions only (precise root set).
@@ -3250,32 +3260,36 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
32503260 // Escape only from those field roots; do nothing if empty.
32513261 if (!SmartPtrFieldRoots.empty ()) {
32523262 ProgramStateRef State = C.getState ();
3253- auto Scan = State->scanReachableSymbols <EscapeTrackedCallback>(SmartPtrFieldRoots);
3263+ auto Scan =
3264+ State->scanReachableSymbols <EscapeTrackedCallback>(SmartPtrFieldRoots);
32543265 ProgramStateRef NewState = Scan.getState ();
32553266 if (NewState != State) {
32563267 C.addTransition (NewState);
3257- } else {
3258- // Fallback: if we have by-value record arguments but no smart pointer fields detected,
3259- // check if any of the arguments are by-value records with smart pointer fields
3268+ } else {
3269+ // Fallback: if we have by-value record arguments but no smart pointer
3270+ // fields detected, check if any of the arguments are by-value records
3271+ // with smart pointer fields
32603272 bool hasByValueRecordWithSmartPtr = false ;
32613273 for (unsigned I = 0 , E = Call.getNumArgs (); I != E; ++I) {
32623274 const Expr *AE = Call.getArgExpr (I);
3263- if (!AE) continue ;
3275+ if (!AE)
3276+ continue ;
32643277 AE = AE->IgnoreParenImpCasts ();
3265-
3266- if (AE->isGLValue ()) continue ;
3278+
3279+ if (AE->isGLValue ())
3280+ continue ;
32673281 QualType T = AE->getType ();
3268- if (!T->isRecordType () || T->isReferenceType ()) continue ;
3269-
3282+ if (!T->isRecordType () || T->isReferenceType ())
3283+ continue ;
3284+
32703285 const bool LooksLikeTemp =
32713286 isa<CXXTemporaryObjectExpr>(AE) ||
3272- isa<MaterializeTemporaryExpr>(AE) ||
3273- isa<CXXConstructExpr>(AE) ||
3274- isa<InitListExpr>(AE) ||
3275- isa<ImplicitCastExpr>(AE) ||
3287+ isa<MaterializeTemporaryExpr>(AE) || isa<CXXConstructExpr>(AE) ||
3288+ isa<InitListExpr>(AE) || isa<ImplicitCastExpr>(AE) ||
32763289 isa<CXXBindTemporaryExpr>(AE);
3277- if (!LooksLikeTemp) continue ;
3278-
3290+ if (!LooksLikeTemp)
3291+ continue ;
3292+
32793293 // Check if this record type has smart pointer fields
32803294 const auto *CRD = T->getAsCXXRecordDecl ();
32813295 if (CRD) {
@@ -3286,16 +3300,18 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
32863300 }
32873301 }
32883302 }
3289- if (hasByValueRecordWithSmartPtr) break ;
3303+ if (hasByValueRecordWithSmartPtr)
3304+ break ;
32903305 }
3291-
3306+
32923307 if (hasByValueRecordWithSmartPtr) {
32933308 ProgramStateRef State = C.getState ();
32943309 RegionStateTy RS = State->get <RegionState>();
32953310 ProgramStateRef NewState = State;
32963311 for (auto [Sym, RefSt] : RS) {
32973312 if (RefSt.isAllocated () || RefSt.isAllocatedOfSizeZero ()) {
3298- NewState = NewState->set <RegionState>(Sym, RefState::getEscaped (&RefSt));
3313+ NewState =
3314+ NewState->set <RegionState>(Sym, RefState::getEscaped (&RefSt));
32993315 }
33003316 }
33013317 if (NewState != State)
@@ -3367,8 +3383,6 @@ void MallocChecker::checkPreCall(const CallEvent &Call,
33673383 if (!FD)
33683384 return ;
33693385
3370-
3371-
33723386 // FIXME: I suspect we should remove `MallocChecker.isEnabled() &&` because
33733387 // it's fishy that the enabled/disabled state of one frontend may influence
33743388 // reports produced by other frontends.
0 commit comments