https://github.com/t-rasmud updated 
https://github.com/llvm/llvm-project/pull/200294

>From 0770839c45c0f859bbcaa41ceb74dd3588b0a685 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Thu, 28 May 2026 15:47:58 -0700
Subject: [PATCH 1/7] [Webkit Checkers][SaferCpp] Detect base-to-derived
 downcasts laundered through void* in MemoryUnsafeCastChecker

Adds a matcher for static_cast<Derived*>(static_cast<void*>(base)), which
previously evaded detection because the outer cast's immediate source expression
is void*, not Base*.

rdar://173770143
---
 .../WebKit/MemoryUnsafeCastChecker.cpp        | 16 +++++++++++----
 .../Checkers/WebKit/memory-unsafe-cast.mm     | 20 ++++++++++++-------
 2 files changed, 25 insertions(+), 11 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index eeaccf9b70524..5461ce66f085f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -122,10 +122,18 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
                          .bind(DerivedNode)))))),
             unless(anyOf(hasSourceExpression(hasDescendant(cxxThisExpr())),
                          hasType(templateTypeParmDecl()))));
-
-  auto ExplicitCast = explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef,
-                                             MatchExprPtrObjC))
-                          .bind(WarnRecordDecl);
+  auto MatchExprPtrVoidCast = cxxStaticCastExpr(
+      hasSourceExpression(cxxStaticCastExpr(
+          hasType(pointerType(pointee(voidType()))),
+          hasSourceExpression(ignoringImpCasts(
+              hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
+      hasTypePointingTo(
+          
cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode))).bind(DerivedNode)));
+
+  auto ExplicitCast =
+      explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef, 
MatchExprPtrObjC,
+                             MatchExprPtrVoidCast))
+          .bind(WarnRecordDecl);
   auto Cast = stmt(ExplicitCast);
 
   auto Matches =
diff --git a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm 
b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
index f9046d7981784..c4208ec7aeac5 100644
--- a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
+++ b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
@@ -1,12 +1,7 @@
 // RUN: %clang_analyze_cc1 
-analyzer-checker=alpha.webkit.MemoryUnsafeCastChecker -verify %s
 
-@protocol NSObject
-+alloc;
--init;
-@end
-
-@interface NSObject <NSObject> {}
-@end
+#include "mock-types.h"
+#include "objc-mock-types.h"
 
 @interface BaseClass : NSObject
 @end
@@ -62,3 +57,14 @@ void testUnrelated(Class1 *c1) {
   // expected-warning@-1{{Unsafe cast from type 'Class1' to an unrelated type 
'Class2'}}
   Class1 *c1_same = reinterpret_cast<Class1*>(c1); // no warning
 }
+
+struct Base : RefCountable { virtual ~Base() {} };
+struct Derived : Base { int extra; };
+
+void fn_cast_01(Base* base) {
+  auto* d1 = static_cast<Derived*>(base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+
+  auto* d2 = static_cast<Derived*>(static_cast<void*>(base));
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+}

>From 0df94218070d192159529a606e33e8a5dabc8ef9 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Thu, 28 May 2026 16:04:54 -0700
Subject: [PATCH 2/7] Fix code formatting

---
 .../Checkers/WebKit/MemoryUnsafeCastChecker.cpp           | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index 5461ce66f085f..4793b28fd5e56 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -127,12 +127,12 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
           hasType(pointerType(pointee(voidType()))),
           hasSourceExpression(ignoringImpCasts(
               hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
-      hasTypePointingTo(
-          
cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode))).bind(DerivedNode)));
+      hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))
+                            .bind(DerivedNode)));
 
   auto ExplicitCast =
-      explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef, 
MatchExprPtrObjC,
-                             MatchExprPtrVoidCast))
+        explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef,
+                             MatchExprPtrObjC, MatchExprPtrVoidCast))
           .bind(WarnRecordDecl);
   auto Cast = stmt(ExplicitCast);
 

>From 65b87980a0787ebef3168cec628ab14da9ab0a9f Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Thu, 28 May 2026 16:44:42 -0700
Subject: [PATCH 3/7] Add matchers for funciton args and returns

---
 .../WebKit/MemoryUnsafeCastChecker.cpp        | 29 ++++++++++++++++---
 .../Checkers/WebKit/memory-unsafe-cast.mm     | 15 +++++++++-
 2 files changed, 39 insertions(+), 5 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index 4793b28fd5e56..265059408116f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -123,10 +123,15 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
             unless(anyOf(hasSourceExpression(hasDescendant(cxxThisExpr())),
                          hasType(templateTypeParmDecl()))));
   auto MatchExprPtrVoidCast = cxxStaticCastExpr(
-      hasSourceExpression(cxxStaticCastExpr(
-          hasType(pointerType(pointee(voidType()))),
-          hasSourceExpression(ignoringImpCasts(
-              hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
+      anyOf(
+          hasSourceExpression(cxxStaticCastExpr(
+              hasType(pointerType(pointee(voidType()))),
+              hasSourceExpression(ignoringImpCasts(
+                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
+          hasSourceExpression(callExpr(
+              hasType(pointerType(pointee(voidType()))),
+              hasAnyArgument(ignoringImpCasts(
+                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode))))))),
       hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))
                             .bind(DerivedNode)));
 
@@ -141,6 +146,22 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
   for (BoundNodes Match : Matches)
     emitDiagnostics(Match, BR, ADC, this, BT);
 
+  // Match calls returning derived type where an argument is 
static_cast<void*>(Base*)
+  auto MatchCallPtrVoidArgCast = callExpr(
+      hasAnyArgument(
+          cxxStaticCastExpr(
+              hasType(pointerType(pointee(voidType()))),
+              hasSourceExpression(ignoringImpCasts(
+                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))
+              .bind(WarnRecordDecl)),
+      hasTypePointingTo(
+          
cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode))).bind(DerivedNode)));
+  auto CallArgCast = stmt(MatchCallPtrVoidArgCast);
+  auto MatchesCallArgCast =
+      match(stmt(forEachDescendant(CallArgCast)), *D->getBody(), 
AM.getASTContext());
+  for (BoundNodes Match : MatchesCallArgCast)
+    emitDiagnostics(Match, BR, ADC, this, BT);
+
   // Match casts between unrelated types and warn
   auto MatchExprPtrUnrelatedTypes = allOf(
       hasSourceExpression(
diff --git a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm 
b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
index c4208ec7aeac5..5a887c49d3cd8 100644
--- a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
+++ b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
@@ -61,10 +61,23 @@ void testUnrelated(Class1 *c1) {
 struct Base : RefCountable { virtual ~Base() {} };
 struct Derived : Base { int extra; };
 
+void* returnCast(Base* base) {
+  return static_cast<void *>(base);
+}
+
+Derived* fnArgCast(void* base) {
+  return static_cast<Derived*>(base);
+}
+
 void fn_cast_01(Base* base) {
   auto* d1 = static_cast<Derived*>(base);
   // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
-
   auto* d2 = static_cast<Derived*>(static_cast<void*>(base));
   // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d3 = static_cast<Derived*>(returnCast(base));
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d4 = fnArgCast(static_cast<void*>(base));
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  fnArgCast(static_cast<void*>(base));
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
 }

>From 9b517452d258ec38f65baa18cf113d4cda015a0a Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Tue, 2 Jun 2026 11:24:26 -0700
Subject: [PATCH 4/7] AST matchers for missed void* laundering cases

---
 .../WebKit/MemoryUnsafeCastChecker.cpp        | 20 ++++++++++---------
 .../Checkers/WebKit/memory-unsafe-cast.mm     | 16 +++++++++++++++
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index 265059408116f..ae3fc2df05545 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -122,9 +122,9 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
                          .bind(DerivedNode)))))),
             unless(anyOf(hasSourceExpression(hasDescendant(cxxThisExpr())),
                          hasType(templateTypeParmDecl()))));
-  auto MatchExprPtrVoidCast = cxxStaticCastExpr(
+  auto MatchExprPtrVoidCast = allOf(
       anyOf(
-          hasSourceExpression(cxxStaticCastExpr(
+          hasSourceExpression(explicitCastExpr(
               hasType(pointerType(pointee(voidType()))),
               hasSourceExpression(ignoringImpCasts(
                   hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
@@ -146,14 +146,16 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
   for (BoundNodes Match : Matches)
     emitDiagnostics(Match, BR, ADC, this, BT);
 
-  // Match calls returning derived type where an argument is 
static_cast<void*>(Base*)
+  // Match calls returning derived type where an argument is a void pointer
+  auto VoidPtrCast = castExpr(
+      hasType(pointerType(pointee(voidType()))),
+      hasSourceExpression(ignoringImpCasts(
+          hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))
+      .bind(WarnRecordDecl);
   auto MatchCallPtrVoidArgCast = callExpr(
-      hasAnyArgument(
-          cxxStaticCastExpr(
-              hasType(pointerType(pointee(voidType()))),
-              hasSourceExpression(ignoringImpCasts(
-                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))
-              .bind(WarnRecordDecl)),
+      hasAnyArgument(anyOf(
+          VoidPtrCast,
+          explicitCastExpr(hasSourceExpression(VoidPtrCast)))),
       hasTypePointingTo(
           
cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode))).bind(DerivedNode)));
   auto CallArgCast = stmt(MatchCallPtrVoidArgCast);
diff --git a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm 
b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
index 5a887c49d3cd8..55b02b2657230 100644
--- a/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
+++ b/clang/test/Analysis/Checkers/WebKit/memory-unsafe-cast.mm
@@ -80,4 +80,20 @@ void fn_cast_01(Base* base) {
   // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
   fnArgCast(static_cast<void*>(base));
   // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d5 = (Derived*)(void*)base;
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d6 = static_cast<Derived*>((void*)base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d7 = (Derived*)reinterpret_cast<void*>(base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d8 = (Derived*)returnCast(base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  fnArgCast((void*)base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  fnArgCast(base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d9 = reinterpret_cast<Derived*>(static_cast<void*>(base));
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
+  auto* d10 = reinterpret_cast<Derived*>((void*)base);
+  // expected-warning@-1{{Unsafe cast from base type 'Base' to derived type 
'Derived'}}
 }

>From 4e1f37c29077bcbc11880cc1d7bbddd888bb87c8 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Tue, 2 Jun 2026 11:25:26 -0700
Subject: [PATCH 5/7] Fix code formatting

---
 .../StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index ae3fc2df05545..cee974c1139bc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -146,7 +146,8 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
   for (BoundNodes Match : Matches)
     emitDiagnostics(Match, BR, ADC, this, BT);
 
-  // Match calls returning derived type where an argument is a void pointer
+  // Match calls returning derived type where an argument is
+  // a void pointer
   auto VoidPtrCast = castExpr(
       hasType(pointerType(pointee(voidType()))),
       hasSourceExpression(ignoringImpCasts(

>From a22ed4384f36d199e83a96e104f3dcfc0f77feb6 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Tue, 2 Jun 2026 11:31:03 -0700
Subject: [PATCH 6/7] Fix formatting

---
 .../WebKit/MemoryUnsafeCastChecker.cpp        | 23 +++++++++----------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index cee974c1139bc..eb55d643e2567 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -148,20 +148,19 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
 
   // Match calls returning derived type where an argument is
   // a void pointer
-  auto VoidPtrCast = castExpr(
-      hasType(pointerType(pointee(voidType()))),
-      hasSourceExpression(ignoringImpCasts(
-          hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))
-      .bind(WarnRecordDecl);
+  auto VoidPtrCast =
+      castExpr(hasType(pointerType(pointee(voidType()))),
+               hasSourceExpression(ignoringImpCasts(
+                   hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))
+          .bind(WarnRecordDecl);
   auto MatchCallPtrVoidArgCast = callExpr(
-      hasAnyArgument(anyOf(
-          VoidPtrCast,
-          explicitCastExpr(hasSourceExpression(VoidPtrCast)))),
-      hasTypePointingTo(
-          
cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode))).bind(DerivedNode)));
+      hasAnyArgument(anyOf(VoidPtrCast,
+                           
explicitCastExpr(hasSourceExpression(VoidPtrCast)))),
+      hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))
+                            .bind(DerivedNode)));
   auto CallArgCast = stmt(MatchCallPtrVoidArgCast);
-  auto MatchesCallArgCast =
-      match(stmt(forEachDescendant(CallArgCast)), *D->getBody(), 
AM.getASTContext());
+  auto MatchesCallArgCast = match(stmt(forEachDescendant(CallArgCast)),
+                                  *D->getBody(), AM.getASTContext());
   for (BoundNodes Match : MatchesCallArgCast)
     emitDiagnostics(Match, BR, ADC, this, BT);
 

>From 3a384c409cb5484d19f3b9d7b9b544f2793ad487 Mon Sep 17 00:00:00 2001
From: Rashmi Mudduluru <[email protected]>
Date: Tue, 2 Jun 2026 12:57:03 -0700
Subject: [PATCH 7/7] Fix formatting

---
 .../WebKit/MemoryUnsafeCastChecker.cpp        | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
index eb55d643e2567..d7224effc6a8d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/MemoryUnsafeCastChecker.cpp
@@ -123,20 +123,19 @@ void MemoryUnsafeCastChecker::checkASTCodeBody(const Decl 
*D,
             unless(anyOf(hasSourceExpression(hasDescendant(cxxThisExpr())),
                          hasType(templateTypeParmDecl()))));
   auto MatchExprPtrVoidCast = allOf(
-      anyOf(
-          hasSourceExpression(explicitCastExpr(
-              hasType(pointerType(pointee(voidType()))),
-              hasSourceExpression(ignoringImpCasts(
-                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
-          hasSourceExpression(callExpr(
-              hasType(pointerType(pointee(voidType()))),
-              hasAnyArgument(ignoringImpCasts(
-                  hasTypePointingTo(cxxRecordDecl().bind(BaseNode))))))),
+      anyOf(hasSourceExpression(explicitCastExpr(
+                hasType(pointerType(pointee(voidType()))),
+                hasSourceExpression(ignoringImpCasts(
+                    hasTypePointingTo(cxxRecordDecl().bind(BaseNode)))))),
+            hasSourceExpression(
+                callExpr(hasType(pointerType(pointee(voidType()))),
+                         hasAnyArgument(ignoringImpCasts(hasTypePointingTo(
+                             cxxRecordDecl().bind(BaseNode))))))),
       hasTypePointingTo(cxxRecordDecl(isDerivedFrom(equalsBoundNode(BaseNode)))
                             .bind(DerivedNode)));
 
   auto ExplicitCast =
-        explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef,
+      explicitCastExpr(anyOf(MatchExprPtr, MatchExprRefTypeDef,
                              MatchExprPtrObjC, MatchExprPtrVoidCast))
           .bind(WarnRecordDecl);
   auto Cast = stmt(ExplicitCast);

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

Reply via email to