https://github.com/Z3rox-dev created 
https://github.com/llvm/llvm-project/pull/181167

## Summary

Add defensive `assert` checks for all `getAs<>()` calls in `CGCUDARuntime.cpp` 
that were previously dereferenced without null verification.

## Details

The file had **8 unchecked `getAs<>()`** calls across `emitGetParamBuf()` and 
`EmitCUDADeviceKernelCallExpr()`, including chained dereferences like:

```cpp
E->getCallee()->getType()->getAs<PointerType>()->getPointeeType();
```

where a null return from `getAs<PointerType>()` would cause an immediate crash 
with no diagnostic.

### Changes:
- Added `assert()` null checks for all `getAs<PointerType>()` and 
`getAs<FunctionProtoType>()` results
- Eliminated **3 redundant `getAs<>()` calls** by caching results in local 
variables (`KernelPT`, `KernelFPT`, `LaunchPT`, `LaunchFPT`)
- Broke chained dereferences into separate, checked steps

### Motivation:
While Sema validation currently prevents these types from being null in 
practice, this change:
1. Follows the established defensive coding pattern used elsewhere in CodeGen 
(e.g., `CGExprScalar.cpp`, `CGObjCMac.cpp`)
2. Provides executable documentation of the implicit type contract
3. Improves debuggability in assertion-enabled builds
4. Makes the code more resilient to future refactoring that might alter Sema 
guarantees

**NFC** (no functional change in release builds — asserts are compiled out).

## Testing
- `check-clang-codegen-cuda`: **75/75 passed**
- `check-clang-sema-cuda`: **99/99 passed**
- `clang-format`: clean


>From 3e8e19bb13be97c40a199f9382c695412edae570 Mon Sep 17 00:00:00 2001
From: Giovanni Baldon <[email protected]>
Date: Thu, 12 Feb 2026 12:00:00 +0000
Subject: [PATCH] [Clang][CodeGen][CUDA] Add missing null-check assertions in
 CGCUDARuntime

Add defensive assert checks for all getAs<>() calls in
CGCUDARuntime.cpp that were previously dereferenced without any
null verification.

The file had 8 unchecked getAs<>() calls across emitGetParamBuf()
and EmitCUDADeviceKernelCallExpr(), including chained dereferences
where a null return would cause an immediate crash.

This also eliminates redundant getAs<>() calls by caching the
result in local variables (LaunchFPT, KernelFPT), which is both
safer and more efficient.

While Sema validation currently prevents these types from being
null in practice, adding assertions follows the established
defensive coding pattern used elsewhere in CodeGen and improves
debuggability in assertion-enabled builds.

NFC (no functional change in release builds).
---
 clang/lib/CodeGen/CGCUDARuntime.cpp | 34 +++++++++++++++++------------
 1 file changed, 20 insertions(+), 14 deletions(-)

diff --git a/clang/lib/CodeGen/CGCUDARuntime.cpp 
b/clang/lib/CodeGen/CGCUDARuntime.cpp
index 9c831b26c3a7b..545233e4f1221 100644
--- a/clang/lib/CodeGen/CGCUDARuntime.cpp
+++ b/clang/lib/CodeGen/CGCUDARuntime.cpp
@@ -27,6 +27,8 @@ static llvm::Value *emitGetParamBuf(CodeGenFunction &CGF,
   auto *GetParamBuf = CGF.getContext().getcudaGetParameterBufferDecl();
   const FunctionProtoType *GetParamBufProto =
       GetParamBuf->getType()->getAs<FunctionProtoType>();
+  assert(GetParamBufProto &&
+         "cudaGetParameterBuffer must have function proto type");
 
   DeclRefExpr *DRE = DeclRefExpr::Create(
       CGF.getContext(), {}, {}, GetParamBuf,
@@ -43,8 +45,10 @@ static llvm::Value *emitGetParamBuf(CodeGenFunction &CGF,
            CGF.getContext().getSizeType());
   // Calculate parameter sizes.
   const PointerType *PT = E->getCallee()->getType()->getAs<PointerType>();
+  assert(PT && "CUDA kernel callee must be a pointer type");
   const FunctionProtoType *FTP =
       PT->getPointeeType()->getAs<FunctionProtoType>();
+  assert(FTP && "CUDA kernel callee must be a function proto type");
   CharUnits Offset = CharUnits::Zero();
   for (auto ArgTy : FTP->getParamTypes()) {
     auto TInfo = CGF.CGM.getContext().getTypeInfoInChars(ArgTy);
@@ -79,14 +83,16 @@ RValue CGCUDARuntime::EmitCUDADeviceKernelCallExpr(
   eval.begin(CGF);
   CGF.EmitBlock(ConfigOKBlock);
 
-  QualType KernelCalleeFuncTy =
-      E->getCallee()->getType()->getAs<PointerType>()->getPointeeType();
+  const auto *KernelPT = E->getCallee()->getType()->getAs<PointerType>();
+  assert(KernelPT && "CUDA kernel callee must be a pointer type");
+  QualType KernelCalleeFuncTy = KernelPT->getPointeeType();
   CGCallee KernelCallee = CGF.EmitCallee(E->getCallee());
   // Emit kernel arguments.
   CallArgList KernelCallArgs;
-  CGF.EmitCallArgs(KernelCallArgs,
-                   KernelCalleeFuncTy->getAs<FunctionProtoType>(),
-                   E->arguments(), E->getDirectCallee());
+  const auto *KernelFPT = KernelCalleeFuncTy->getAs<FunctionProtoType>();
+  assert(KernelFPT && "CUDA kernel callee must be a function proto type");
+  CGF.EmitCallArgs(KernelCallArgs, KernelFPT, E->arguments(),
+                   E->getDirectCallee());
   // Copy emitted kernel arguments into that parameter buffer.
   RawAddress CfgBase(Config, CGM.Int8Ty,
                      /*Alignment=*/CharUnits::fromQuantity(64));
@@ -101,22 +107,22 @@ RValue CGCUDARuntime::EmitCUDADeviceKernelCallExpr(
   }
   // Make `cudaLaunchDevice` call, i.e. E->getConfig().
   const CallExpr *LaunchCall = E->getConfig();
-  QualType LaunchCalleeFuncTy = LaunchCall->getCallee()
-                                    ->getType()
-                                    ->getAs<PointerType>()
-                                    ->getPointeeType();
+  const auto *LaunchPT =
+      LaunchCall->getCallee()->getType()->getAs<PointerType>();
+  assert(LaunchPT && "CUDA launch callee must be a pointer type");
+  QualType LaunchCalleeFuncTy = LaunchPT->getPointeeType();
   CGCallee LaunchCallee = CGF.EmitCallee(LaunchCall->getCallee());
   CallArgList LaunchCallArgs;
-  CGF.EmitCallArgs(LaunchCallArgs,
-                   LaunchCalleeFuncTy->getAs<FunctionProtoType>(),
-                   LaunchCall->arguments(), LaunchCall->getDirectCallee());
+  const auto *LaunchFPT = LaunchCalleeFuncTy->getAs<FunctionProtoType>();
+  assert(LaunchFPT && "CUDA launch callee must be a function proto type");
+  CGF.EmitCallArgs(LaunchCallArgs, LaunchFPT, LaunchCall->arguments(),
+                   LaunchCall->getDirectCallee());
   // Replace func and paramterbuffer arguments.
   LaunchCallArgs[0] = CallArg(RValue::get(KernelCallee.getFunctionPointer()),
                               CGM.getContext().VoidPtrTy);
   LaunchCallArgs[1] = CallArg(RValue::get(Config), CGM.getContext().VoidPtrTy);
   const CGFunctionInfo &LaunchCallInfo = 
CGM.getTypes().arrangeFreeFunctionCall(
-      LaunchCallArgs, LaunchCalleeFuncTy->getAs<FunctionProtoType>(),
-      /*ChainCall=*/false);
+      LaunchCallArgs, LaunchFPT, /*ChainCall=*/false);
   CGF.EmitCall(LaunchCallInfo, LaunchCallee, ReturnValue, LaunchCallArgs,
                CallOrInvoke,
                /*IsMustTail=*/false, E->getExprLoc());

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

Reply via email to