You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CUDA最简内核触发非法内存访问错误的原因与调试咨询

CUDA非法内存访问问题排查与解决

环境信息

  • 系统:Ubuntu 22.04
  • CUDA版本:12.2.128
  • GPU:GeForce RTX 2060

问题代码

#include "cuda_runtime.h"

#include <iostream>
#include <stdexcept>
#include <cstdlib>
#include <cmath>

#define CUDACHECK(E) if (E != cudaSuccess) \
    { \
        std::cerr << "Fatal error [line " << __LINE__ << "]: " << cudaGetErrorString(E) << ".\n"; \
        std::abort(); \
    }

#define ASSERT(B) if (!(B)) \
    { \
        std::cerr << "Fatal error: test failed in line " << __LINE__ << ".\n"; \
        std::abort(); \
    }

__global__ void fill(float* x, const std::size_t& size, const float& value)
{
    const auto tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < size)
    {
        x[tid] = value;
    }
}


int main()
{
    // allocate device data
    const auto size = std::size_t{10000};
    auto* xD = static_cast<float*>(nullptr);
    CUDACHECK(cudaMalloc(&xD, size * sizeof(float)));
    ASSERT(xD != nullptr);
    
    // run fill kernel
    const auto fill_value = static_cast<float>(-1.0);
    fill<<<1,1>>>(xD, size, fill_value);
    CUDACHECK(cudaDeviceSynchronize());
    
    // <--- control doesn't get past here!
    
    // copy to host
    //auto* xH = reinterpret_cast<float*>(std::malloc(size * sizeof(float)));
    //ASSERT(xH != nullptr);
    //CUDACHECK(cudaMemcpy(xH, xD, size * sizeof(float), cudaMemcpyDeviceToHost));
    
    //constexpr auto tol = std::is_same<float, float>::value ? static_cast<float>(1E-5) : static_cast<float>(1E-10);
    //for (auto ii = std::size_t{}; ii < size; ++ii)
    //{
    //    ASSERT(std::fabs(fill_value - xH[ii]) < tol);
    //}
    
    // free
    CUDACHECK(cudaFree(reinterpret_cast<void*>(xD)));
    //std::free(xH);
    
    // tests have been passed
    std::cout << "Tests passed! Hallo, CUDA world!" << std::endl;
    
    return 0;
}

运行输出

Fatal error [line 42]: an illegal memory access was encountered.
Aborted (core dumped)

Compute-sanitizer检测结果

========= COMPUTE-SANITIZER
========= Invalid __global__ read of size 8 bytes
=========     at 0x20 in fill(float *, const unsigned long &, const float &)
=========     by thread (0,0,0) in block (0,0,0)
=========     Address 0x7ffc902b1f30 is out of bounds
=========     and is 639439150385 bytes after the nearest allocation at 0x7f67aea00000 of size 512 bytes
=========     Saved host backtrace up to driver entry point at kernel launch time
=========     Host Frame: [0x32e950]
=========                in /lib/x86_64-linux-gnu/libcuda.so.1
=========     Host Frame:libcudart_static_4d8b33a106dceb3c07a56e26de61f2d53bb62a68 [0x1093e]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:cudaLaunchKernel [0x70b4e]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:cudaError cudaLaunchKernel<char>(char const*, dim3, dim3, void**, unsigned long, CUstream_st*) [0xb235]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:__device_stub__Z4fillPfRKmRKf(float*, unsigned long const*, float const*) [0xb094]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:fill(float*, unsigned long const&, float const&) [0xb0f7]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:main [0xadaa]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:../sysdeps/nptl/libc_start_call_main.h:58:__libc_start_call_main [0x29d90]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:../csu/libc-start.c:379:__libc_start_main [0x29e40]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:_start [0xab15]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
========= 
========= Program hit cudaErrorLaunchFailure (error 719) due to "unspecified launch failure" on CUDA API call to cudaDeviceSynchronize.
=========     Saved host backtrace up to driver entry point at error
=========     Host Frame: [0x47e786]
=========                in /lib/x86_64-linux-gnu/libcuda.so.1
=========     Host Frame:cudaDeviceSynchronize [0x48a64]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:main [0xadaf]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:../sysdeps/nptl/libc_start_call_main.h:58:__libc_start_call_main [0x29d90]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:../csu/libc-start.c:379:__libc_start_main [0x29e40]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:_start [0xab15]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
========= 
Fatal error [line 42]: ========= Program hit cudaErrorLaunchFailure (error 719) due to "unspecified launch failure" on CUDA API call to cudaDeviceSynchronize.
=========     Saved host backtrace up to driver entry point at error
=========     Host Frame: [0x47e786]
=========                in /lib/x86_64-linux-gnu/libcuda.so.1
=========     Host Frame:cudaDeviceSynchronize [0x48a64]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:main [0xadfb]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
=========     Host Frame:../sysdeps/nptl/libc_start_call_main.h:58:__libc_start_call_main [0x29d90]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:../csu/libc-start.c:379:__libc_start_main [0x29e40]
=========                in /lib/x86_64-linux-gnu/libc.so.6
=========     Host Frame:_start [0xab15]
=========                in /home/nitin/Documents/code/gpu/device/./hw_cuda
========= 
unspecified launch failure.
========= Error: process didn't terminate successfully
========= Target application returned an error
========= ERROR SUMMARY: 3 errors

问题解答

1. 非法内存访问错误的成因

错误核心在于CUDA Kernel不能直接接收主机端的引用类型参数。代码中fill Kernel的参数const std::size_t& size和const float& value是引用类型,这些引用指向的是主机栈上的变量内存地址。而GPU设备无法直接访问主机的栈内存,当Kernel尝试读取size和value时,会去访问主机端的内存地址(从sanitizer输出的0x7ffc902b1f30可以判断是主机栈地址,设备内存地址通常以0x7f开头),导致非法内存访问。

2. 调试定位与解决方法

定位步骤

  • 查看compute-sanitizer的错误输出:明确指出错误发生在fill Kernel中,是对主机地址的非法读取。
  • 区分内存地址类型:0x7ffc开头的地址属于主机栈内存,GPU无法直接访问,说明Kernel尝试访问了主机端的数据。
  • 检查Kernel参数:发现参数使用了引用类型,这是CUDA编程的常见误区——Kernel参数传递应避免使用主机端的引用或指针(除非使用统一内存且配置正确)。

解决方法

将Kernel的引用参数改为值传递,修改后的fill Kernel如下:

__global__ void fill(float* x, const std::size_t size, const float value)
{
    const auto tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < size)
    {
        x[tid] = value;
    }
}

这样,size和value会被直接拷贝到设备端供Kernel使用,避免了对主机内存的非法访问。

内容的提问来源于stack exchange,提问作者Nitin Malapally

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 18:08:09