OpenCL程序调用clBuildProgram触发段错误求助
OpenCL程序调用
clBuildProgram触发段错误排查 问题描述
我正在用C语言编写首个OpenCL程序,目标是快速计算曼德博集合,但调用clBuildProgram时触发了段错误。即使注释掉内核代码的所有主体内容,程序仍会出现段错误。
内核代码
const char *mandelbrot_kernel_source = "\n" "__kernel void mb(\n" " __global unsigned char *out,\n" " const unsigned int width,\n" " const double real_start,\n" " const double imag_start,\n" " const double stepsize,\n" " const unsigned int max_iters,\n" " const double bailout\n" ") {\n" " unsigned int w = get_global_id(0);\n" " unsigned int h = get_global_id(1);\n" " double real = real_start + w * stepsize;\n" " double imag = imag_start - h * stepsize;\n" " unsigned int iters = derbail(real, imag, max_iters, bailout);\n" " if (iters > UCHAR_MAX) {\n" " out[h * width + w] = UCHAR_MAX;\n" " } else {\n" " out[h * width + w] = iters;\n" " }\n" "}\n";
主机端构建执行代码(至段错误触发行)
int gpu_main(double real_center, double imag_center, unsigned int width, unsigned int height, double stepsize, unsigned int max_iters, double bailout, const char output[256]) { double real_start = real_center - width * stepsize / 2; double imag_start = imag_center + height * stepsize / 2; cl_int err; cl_uint num_platforms; err = clGetPlatformIDs(0, NULL, &num_platforms); if (num_platforms == 0) { printf("Zero platforms! (error code: %d)\n", err); return EXIT_FAILURE; } cl_platform_id platforms[num_platforms]; err = clGetPlatformIDs(num_platforms, platforms, NULL); cl_device_id device_id; for (int i = 0; i < num_platforms; ++i) { err = clGetDeviceIDs(platforms[i], CL_DEVICE_TYPE_DEFAULT, 1, &device_id, NULL); if (err == CL_SUCCESS) { break; } } if (device_id == NULL) { printf("Failed to acquire device_id (error code: %d)\n", err); return EXIT_FAILURE; } cl_context context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); if (err != CL_SUCCESS) { printf("Failed to build context (error code: %d)\n", err); } cl_command_queue commands = clCreateCommandQueueWithProperties(context, device_id, 0, &err); if (err != CL_SUCCESS) { printf("Failed to build commands (error code: %d)\n", err); } cl_program program = clCreateProgramWithSource( context, 1, (const char **)&mandelbrot_kernel_source, NULL, &err); if (err != CL_SUCCESS) { printf("Failed to create program (error code: %d)\n", err); } err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
Valgrind错误输出(翻译后)
==12345== Memcheck,内存错误检测器 ==12345== 版权所有 (C) 2002-2022,遵循GNU GPL协议,由Julian Seward等人开发 ==12345== 使用Valgrind-3.19.0和LibVEX;重新运行加-h参数查看版权信息 ==12345== 命令:./mandelbrot ==12345== 父进程PID:6789 ==12345== ==12345== 使用了未初始化的8字节值 ==12345== 位于0x123456: clBuildProgram (在/usr/lib/libOpenCL.so.1中) ==12345== 由0x789ABC: gpu_main (mandelbrot.c:123)调用 ==12345== 由0x456DEF: main (mandelbrot.c:456)调用 ==12345== 未初始化的值由栈分配产生 ==12345== 位于0x789012: gpu_main (mandelbrot.c:78) ==12345== ==12345== 无效读取,大小为8字节 ==12345== 位于0x123456: clBuildProgram (在/usr/lib/libOpenCL.so.1中) ==12345== 由0x789ABC: gpu_main (mandelbrot.c:123)调用 ==12345== 由0x456DEF: main (mandelbrot.c:456)调用 ==12345== 地址0x1234567不在栈、堆分配或(最近)释放的区域内 ==12345== ==12345== 进程因信号11(SIGSEGV)的默认操作终止 ==12345== 在地址0x1234567处的访问不在映射区域内 ==12345== 位于0x123456: clBuildProgram (在/usr/lib/libOpenCL.so.1中) ==12345== 由0x789ABC: gpu_main (mandelbrot.c:123)调用 ==12345== 由0x456DEF: main (mandelbrot.c:456)调用 ==12345== 如果你认为这是程序主线程栈溢出导致的(可能性低但存在),可以尝试使用--main-stacksize=标志增大主线程栈大小。本次运行使用的主线程栈大小为8388608字节。 ==12345== ==12345== 堆摘要: ==12345== 退出时仍在使用:0块,0字节 ==12345== 堆总使用情况:0次分配,0次释放,0字节分配 ==12345== ==12345== 所有堆块均已释放——无内存泄漏 ==12345== ==12345== 要查看检测到的错误和被抑制的错误列表,重新运行时加-s参数 ==12345== 错误摘要:2个上下文共2个错误(被抑制:0个上下文共0个)
问题分析与解决建议
核心问题
从Valgrind输出和代码逻辑看,段错误源于未初始化的变量被传递给OpenCL API,以及错误处理不严格导致无效对象被复用。
具体修复步骤
初始化
device_id变量
声明时直接初始化为NULL,确保后续空指针判断可靠:cl_device_id device_id = NULL;严格处理所有OpenCL函数的错误返回
任何OpenCL函数调用失败后,立即终止程序,避免使用无效对象继续执行。例如:cl_context context = clCreateContext(NULL, 1, &device_id, NULL, NULL, &err); if (err != CL_SUCCESS) { printf("Failed to build context (error code: %d)\n", err); return EXIT_FAILURE; }对
clCreateCommandQueueWithProperties和clCreateProgramWithSource执行同样的修改。修正内核代码的语法隐患
移除内核字符串末尾的多余分号,将}\n";;改为}\n";。补全内核中未定义的函数
内核中调用的derbail函数未实现,后续需要补充该函数的OpenCL内核代码,否则编译时会报错。
内容的提问来源于stack exchange,提问作者Lemma
相关产品推荐
相关产品推荐

