Author: Fady Farag
Date: 2026-10-13T23:09:25-07:00
New Revision: 6eaf6124b077de6d8726eb50062c02a579d053f3

URL: 
https://github.com/llvm/llvm-project/commit/6eaf6124b077de6d8726eb50062c02a579d053f3
DIFF: 
https://github.com/llvm/llvm-project/commit/6eaf6124b077de6d8726eb50062c02a579d053f3.diff

LOG: [alpha.webkit.UncountedLocalVarsChecker] Only skip the destructor of a 
null smart pointer temporary bound as const (#231715)

Previously, `TrivialFunctionAnalysis` skipped the destructor check of a
temporary owning smart pointer whenever it was constructed to hold
nullptr. That is correct when the temporary is bound to a const
reference, but a temporary materialized as non-const can be given a new
value before it is destructed, so its destructor may delete the object.
This caused a missing warning for any raw pointer/reference local
variable whose guardian was swapped into the temporary. This only skips
the destructor check when the null temporary is materialized through a
NoOp cast to const.

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
    clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 0a98dc6357bd6..afcb5bf2cb692 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -1272,6 +1272,13 @@ class TrivialFunctionAnalysisVisitor
   }
 
   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *VMT) {
+    if (auto *ICE = dyn_cast<ImplicitCastExpr>(VMT->getSubExpr());
+        ICE && ICE->getCastKind() == CK_NoOp &&
+        ICE->getType().isConstQualified()) {
+      if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(ICE->getSubExpr());
+          BTE && isNullSmartPtr(BTE->getSubExpr()))
+        return Visit(BTE->getSubExpr());
+    }
     return Visit(VMT->getSubExpr());
   }
 
@@ -1330,8 +1337,7 @@ class TrivialFunctionAnalysisVisitor
 
   bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE) {
     if (auto *Temp = BTE->getTemporary()) {
-      if (!isNullSmartPtr(BTE->getSubExpr()) &&
-          !IsFunctionTrivial(Temp->getDestructor()))
+      if (!IsFunctionTrivial(Temp->getDestructor()))
         return false;
     }
     return Visit(BTE->getSubExpr());

diff  --git a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
index e26bd87e0d425..30560987d3130 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-local-vars.cpp
@@ -1052,4 +1052,25 @@ void non_null_temporary(RefCountable& obj) {
   }
 }
 
+void null_temporary_swapped_with_guardian(RefCountable& src) {
+  RefPtr<RefCountable> obj = &src;
+  {
+    auto* foo = obj.get();
+    // expected-warning@-1{{Local variable 'foo' is a raw pointer to 
RefPtr-capable type 'RefCountable' [alpha.webkit.UncountedLocalVarsChecker]}}
+    RefPtr<RefCountable>().swap(obj);
+    foo->trivial();
+  }
+}
+
+void moveInto(RefPtr<RefCountable>&& dst, RefPtr<RefCountable>& src) { 
dst.swap(src); }
+
+void null_temporary_filled_by_callee(RefPtr<RefCountable> obj) {
+  {
+    auto* foo = obj.get();
+    // expected-warning@-1{{Local variable 'foo' is a raw pointer to 
RefPtr-capable type 'RefCountable' [alpha.webkit.UncountedLocalVarsChecker]}}
+    moveInto(RefPtr<RefCountable>(), obj);
+    foo->trivial();
+  }
+}
+
 } // namespace hash_table_empty_value


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to