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

调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:50:28