未初始化的读取和不可寻址的访问错误

Posted

技术标签:

【中文标题】未初始化的读取和不可寻址的访问错误【英文标题】:Unitialized read and unaddressable access errors 【发布时间】:2015-03-21 18:45:20 【问题描述】:

我在 Windows 7 下执行了 drmemory 来检查我的内存泄漏并发现了一些对我来说相当奇怪的东西:

Error #1: UNINITIALIZED READ: reading 0x08842fdc-0x08842fe0 4 byte(s)
# 0 ig7icd32.dll!DllMain                             +0x56017  (0x5a995ec7 <ig7icd32.dll+0xd5ec7>)
# 1 ig7icd32.dll!DllMain                             +0x54bad  (0x5a994a5e <ig7icd32.dll+0xd4a5e>)
# 2 AbstractVertexData::vertexAttribPtr               [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Graphics/AbstractVertexData.cpp:36]
# 3 DrawBuffers::buildBuffers                         [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Graphics/DrawBuffers.cpp:49]
# 4 DrawBuffers::DrawBuffers                          [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Graphics/DrawBuffers.cpp:14]
# 5 Core::Load                                        [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Core/Load.cpp:178]
# 6 main                                              [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/main.cpp:10]

这个错误指向这段代码,更准确地说是最后一行:

glVertexAttribPointer(layout,
                      getShaderAttribs()[layout]->nbComponents,
                      static_cast<GLenum>(getShaderAttribs()[layout]->attribDataType),
                      getShaderAttribs()[layout]->shouldNormalize,
                      getVertexStride(layout),
                      reinterpret_cast<const void*>(getVertexAttribStart(layout)));

OpenGL 想要的最后一个参数是 const GLvoid* (const void*)。它在语义上是一个 int,表示属性数组的偏移量。无论如何,这条线工作得很好,但我想摆脱这个警告。我不能使用引用,因为函数 getVertexAttribStart 返回一个值而不是指针。我也不想使用 C 类型转换,因为它会杀死非洲的孩子(你知道,C 是魔鬼啊)。

还有这个警告:

Error #4: UNADDRESSABLE ACCESS beyond heap bounds: reading 0x0863fcc4-0x0863fcc8 4 byte(s)
# 0 ig7icd32.dll!DllMain                   +0x52721  (0x5a9925d1 <ig7icd32.dll+0xd25d1>)
# 1 ig7icd32.dll!DllMain                   +0x52660  (0x5a992511 <ig7icd32.dll+0xd2511>)
# 2 ig7icd32.dll!DllMain                   +0x516e7  (0x5a991598 <ig7icd32.dll+0xd1598>)
# 3 DrawBuffers::~DrawBuffers               [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Graphics/DrawBuffers.cpp:23]
# 4 DrawBuffers::~DrawBuffers               [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Graphics/DrawBuffers.cpp:26]
# 5 Core::Unload                            [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/Engine/Core/Unload.cpp:6]
# 6 main                                    [D:/CodeBlocks Workspace/Tests/BasicScene_Tests/BasicScene_InitialTest/main.cpp:23]

这个警告的代码:

DrawBuffers::~DrawBuffers()

    glDeleteBuffers(1, &ibo);
    glDeleteBuffers(1, &vbo); // I'm the line 23!!!
    glDeleteVertexArrays(1, &vao);
    delete vertexData;

首先,什么是 vao、vbo 和 ibo 变量?它们是整数;实际上 OpenGL 中的索引指向 VRAM 中的一些数据(我不是专家)。它们保证被初始化并且只在这个析构函数中被销毁。证据是我的应用程序运行良好。有没有办法修复这个 drmemory 的警告或摆脱它?

这是我的引擎的概念(你需要 draw.io):https://drive.google.com/file/d/0B5dq0OS4n55JcHJqcTBmZHJWYjg/view?usp=sharing

【问题讨论】:

顺便说一句,你为什么不写一些像getVertexAttribStartAddr (layout) 这样返回const GLvoid * 的东西呢?您可以将此参数视为int,但出于可移植性考虑,我建议不要这样做。 GL 需要一个整数值,其位数与主机的数据指针类型一样多。 intptr_t 基本上是您将用于此的类型。 嗯,我刚试过,我有点需要转换我的 intptr_t,即使它在 return 语句中。 【参考方案1】:

首先,什么是 vao、vbo 和 ibo 变量?它们是整数;实际上 OpenGL 中的索引指向 VRAM 中的一些数据(我不是专家)。它们保证被初始化并且只在这个析构函数中被销毁。证据是我的应用程序运行良好。有没有办法修复这个 drmemory 的警告或摆脱它?

虽然与您的问题无关,但知道vaovboibo 是OpenGL 中的保留名称可能会有所帮助。从技术上讲,它们不必与任何数据相关联(它们将在调用glGenBuffers (...)glGenArrays (...) 之后立即以这种状态存在,但在绑定它们之前)。在像 C++ 这样的语言中没有简单的类比,因为如果你在 C++ 中new 某个对象,它将立即调用构造函数 - GL 推迟对象的构造,直到第一次绑定名称。

至于你的实际问题,你为你的类调用了析构函数两次。我不知道为什么您显示的小代码会发生这种情况,但它解释了为什么获取vbo 的地址会产生无效的堆地址。

【讨论】:

其实析构函数只被调用一次。我刚刚调试了它,这很有意义。我有一个在 Load.cpp 中创建并在 Unload.cpp 中销毁的 DrawBuffers 变量。但!我刚刚注意到一些事情:如果我在删除我的 vao、vbo 和 ibo 之前删除我的着色器会不会有问题? 另外,我的代码非常庞大。我的意思是,有很多代码行,我不知道将它提供给您并向您展示所有内容的最佳方式。 *巨大是相对的 好的,我刚刚重新测试,你是对的,析构函数被调用了两次。奇怪的是,当我到处放断点的时候,第一次停在析构函数的末尾,然后下一次又到了顶部。【参考方案2】:

我花了一些时间,但我忘记了一些非常重要的事情:

一般规则是,如果您不能保证 OpenGL RAII 对象会在上下文仍然存在时被销毁,则不要将 OpenGL 对象包装在 RAII C++ 类中。 glDeleteBuffers() crashes during destructor call

在我的主循环中,我在卸载数据之前关闭了窗口,即上下文。

【讨论】:

以上是关于未初始化的读取和不可寻址的访问错误的主要内容,如果未能解决你的问题,请参考以下文章

jquery 数据表:“未捕获的类型错误:无法读取未定义的属性‘长度’”在销毁和重新初始化后。表作为数据源

c - 无法理解为什么我有这些错误:无效读取大小1和Syscall参数unlink(路径名)指向不可寻址的字节

将数据复制/扫描/读取到未初始化的指针时发生崩溃或“分段错误”

CORBA.TRANSIENT 的考虑事项:初始和转发的 IOR 不可访问 vmcid:IBM 次要代码:E07 错误

数据表插件错误未捕获的类型错误:无法读取未定义的属性“mData”

C指针