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
