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

错误调用glGenBuffers致无关指针playerFaces异常的原因解析

问题:未显式修改的指针在OpenGL调用后意外变更

代码片段

主逻辑代码

Object* object = game->scene.worldObjects[0];
Face* playerFaces = NULL;
int playerFaceCount = 0;
traverseBSP(object->collisionMesh, currentCamera->position, &playerFaces, &playerFaceCount);
printf("PF: %p\n", playerFaces);

glDepthMask(GL_TRUE);
glGenBuffers(GL_ARRAY_BUFFER, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);

printf("PF: %p\n", playerFaces);

traverseBSP函数实现

void traverseBSP(BSPNode* node, vec3 position, Face** faceBuffer, int* faceCountBuffer)
{
    if (node->front == NULL && node->back == NULL)
    {
        //leaf node... allocate memory to faceBuffer and fill it
        printf("fb** = %p\n", faceBuffer);
        printf("fb* = %p\n", *faceBuffer);
        *faceBuffer = (Face*)malloc(node->faceCount * sizeof(Face));
        printf("fb* after malloc  = %p\n", *faceBuffer);
        for (int i = 0; i < node->faceCount; i++)
        {
            (*faceBuffer)[i] = node->faces[i];
        }
        *faceCountBuffer = node->faceCount;
        return;
    }

    Plane np = node->splittingPlane;
    float d = np.normal.x * position.x + np.normal.y * position.y + np.normal.z * position.z + np.distance;
    if (d > 0)
    {
        traverseBSP(node->front, position, faceBuffer, faceCountBuffer);
    }
    else
    {
        traverseBSP(node->back, position, faceBuffer, faceCountBuffer);
    }
}

预期与实际输出

预期输出

fb** = 0x723a97467e40
fb* = (nil)
fb* after malloc  = 0x519000038e80
PF: 0x519000038e80
PF: 0x519000038e80

实际输出

fb** = 0x723a97467e40
fb* = (nil)
fb* after malloc  = 0x519000038e80
PF: 0x519000038e80
PF: 0xd0000000c

问题原因

核心问题是错误调用glGenBuffers导致内存越界写入:

  • glGenBuffers的标准签名是void glGenBuffers(GLsizei n, GLuint* buffers);,第一个参数n是要生成的缓冲区对象数量,第二个参数buffers是存储生成ID的数组指针。
  • 你错误地将GL_ARRAY_BUFFER(枚举值为0x8892)作为第一个参数传入,这会让OpenGL认为你要生成0x8892个缓冲区ID,并尝试从&VBO指向的地址开始,连续写入这么多GLuint类型的值。
  • 由于VBO和playerFaces在栈上的内存位置相邻,OpenGL的越界写入直接覆盖了playerFaces的内存空间,导致其值被篡改。

调试方法

  • 内存布局检查:在代码中打印&playerFaces和&VBO的地址,确认两者是否相邻(或处于连续内存区域)。
  • 内存检测工具:使用AddressSanitizer(编译时加-fsanitize=address)或Valgrind运行程序,工具会直接检测到越界写入的问题并给出具体位置。
  • 断点调试:在glGenBuffers调用前后设置断点,查看playerFaces内存的变化,确认是该调用导致的篡改。

修复方案

按照glGenBuffers的正确用法调用:

// 第一个参数传1(生成1个缓冲区),第二个参数传存储ID的指针
glGenBuffers(1, &VBO);

关于0xd0000000c的额外解释

这个值是OpenGL越界写入产生的非法数据:

  • 当OpenGL尝试写入0x8892个GLuint值时,VBO的栈内存空间不足以容纳这么多数据,写入操作会持续覆盖后续的栈内存,而playerFaces正好在这个覆盖路径上。
  • 0xd0000000c并非有效的OpenGL缓冲区ID(正常ID是从1开始的小整数),它只是越界写入过程中覆盖到playerFaces内存的某个随机值,具体数值取决于栈内存布局和OpenGL的内部写入逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 21:47:05