调用glGetProgramResourceName()触发访问违规错误排查
OpenGL调用glGetProgramResourceName()触发访问违规的排查与解决
尝试通过着色器程序句柄调用glGetProgramResourceName()获取uniform块名称时,操作std::vector<GLchar>触发访问违规错误(错误码0xC0000005: 执行位置0x0000000000000000处发生访问违规),无法定位原因,目标是获取UBO名称Matrices_XY。
相关C++代码
GLint numUniformBlocks = 0; GLint maxLength; GLsizei size; glGetProgramiv(handle_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); glGetProgramInterfaceiv(handle_, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numUniformBlocks); std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE}; std::array<GLint, 3> blockData{}; for (int blockIx = 0; blockIx < numUniformBlocks; ++blockIx) { glGetProgramResourceiv(handle_,GL_UNIFORM_BLOCK,blockIx,blockProperties.size(), blockProperties.data(), blockData.size(),nullptr,blockData.data() ); //Retrieve name //std::string blockName(blockData[0], ' '); //std::vector<char> blockName(blockData[0]); std::vector<GLchar> blockName; //Yes, not std::string. There's a reason for that. blockName.resize(blockData[0]); //GLchar* blockName = static_cast<GLchar*>(malloc(maxLength)); glGetProgramResourceName(handle_, GL_UNIFORM_BLOCK, blockIx, blockName.size(), &size, blockName.data()); }
着色器代码
#version 400 layout (location = 0) in vec4 VertexPosition; out vec2 TexCoords; layout(std140) uniform Matrices_XY{ mat4 cameraToClipMatrix; mat4 worldToCameraMatrix; mat4 modelToWorldMatrix; mat4 NormalMatrix; }; void main(){ gl_Position = cameraToClipMatrix * worldToCameraMatrix * modelToWorldMatrix * vec4(VertexPosition.xy, 0.0, 1.0); TexCoords = VertexPosition.zw; }
已尝试的方法
- 改用
std::string、std::vector<char>、malloc分配内存,均触发错误 - 手动追加
'\0'并调整传入函数的缓冲区大小,问题依旧
开发环境
- OpenGL 4.6
- C++20
- MSVC 2022/17.3.6
- Windows 10专业版x64
- MFC框架
问题排查与解决方案
访问违规0xC0000005核心原因是空指针或非法内存访问,针对代码逐一排查:
1. 确认程序句柄有效性
确保handle_是成功链接的OpenGL程序对象,未被提前销毁。链接失败的程序句柄调用GL函数会触发未定义行为:
GLint linkStatus = GL_FALSE; glGetProgramiv(handle_, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLchar infoLog[1024]; glGetProgramInfoLog(handle_, 1024, nullptr, infoLog); // 输出链接错误日志排查问题 }
2. 修正glGetProgramResourceiv参数类型
代码中blockData.size()返回size_t类型,但GL函数期望GLsizei,类型不匹配可能导致参数解析错误,使blockData[0](名称长度)值异常:
glGetProgramResourceiv(handle_, GL_UNIFORM_BLOCK, blockIx, static_cast<GLsizei>(blockProperties.size()), blockProperties.data(), static_cast<GLsizei>(blockData.size()), nullptr, blockData.data());
3. 为字符串终止符预留缓冲区空间
blockData[0]是UBO名称的长度(不含\0),若vector仅分配blockData[0]大小,glGetProgramResourceName写入终止符时会越界破坏内存:
// 预留终止符空间 std::vector<GLchar> blockName(blockData[0] + 1); glGetProgramResourceName(handle_, GL_UNIFORM_BLOCK, blockIx, static_cast<GLsizei>(blockName.size()), &size, blockName.data());
修正后的完整代码
GLint numUniformBlocks = 0; GLint maxLength; GLsizei size; GLint linkStatus = GL_FALSE; glGetProgramiv(handle_, GL_LINK_STATUS, &linkStatus); if (linkStatus != GL_TRUE) { GLchar infoLog[1024]; glGetProgramInfoLog(handle_, 1024, nullptr, infoLog); // 处理链接错误 } glGetProgramiv(handle_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength); glGetProgramInterfaceiv(handle_, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &numUniformBlocks); std::array<GLenum, 3> blockProperties{GL_NAME_LENGTH, GL_NUM_ACTIVE_VARIABLES, GL_BUFFER_DATA_SIZE}; std::array<GLint, 3> blockData{}; for (int blockIx = 0; blockIx < numUniformBlocks; ++blockIx) { glGetProgramResourceiv(handle_, GL_UNIFORM_BLOCK, blockIx, static_cast<GLsizei>(blockProperties.size()), blockProperties.data(), static_cast<GLsizei>(blockData.size()), nullptr, blockData.data()); std::vector<GLchar> blockName(blockData[0] + 1); glGetProgramResourceName(handle_, GL_UNIFORM_BLOCK, blockIx, static_cast<GLsizei>(blockName.size()), &size, blockName.data()); // 转换为std::string使用 std::string uboName(blockName.data()); }
内容的提问来源于stack exchange,提问作者user3533871
相关产品推荐
相关产品推荐

