矩阵类的写入大小为 4 无效(使用 valgrind)
我有一个简单的矩阵类,用于与 opengl 一起使用(es 2.0,afaik 对于该特定版本的 opengl 没有任何内置版本)。
它基本上只不过是一个在构造函数中调整大小以包含 16 个浮点的向量(我选择了一个向量,而不是一个仅包含 16 个浮点数组的 = 运算符),以及一些在 opengl 上下文中有用的便利函数。无论如何,这些方便的结构之一将单位矩阵加载到向量中,它是:
void Matrix::loadIdentity()
{
matrix.resize(16, 0);
for(int i = 0; i < 16; i++)
matrix[i] = 0.0f;
for(int i = 0; i < 4; i++) {
matrix[i * 4 + i] = 1.0f;
}
}
其中矩阵是:
std::vector<float>
行说:
matrix.resize(16, 0);
是为了确保大小实际上是 16 个浮点数,尽管它也是在构造函数中完成的,并且我我不相信最终会需要它,但现在是为了消除一个可能的错误,使调试变得更容易。
Valgrind 告诉我这个函数,特别是这一行:
matrix[i] = 0.0f;
导致无效的写入大小为 4,这听起来很可疑,就像我以某种方式调用matrix[16] = 0.0f;。然而,我应该只从 0 到 15。值得注意的一件有趣的事情是 valgrind 还说正在写入的相关内存是由矩阵的析构函数分配的,更具体地说,是由向量的析构函数分配的。
Address 0x150f8280 is 0 bytes inside a block of size 64 free'd 1: operator delete(void*) in /build/buildd/valgrind-3.6.1/coregrind/m_replacemalloc/vg_replace_malloc.c:387
2: __gnu_cxx::new_allocator<float>::deallocate(float*, unsigned long) in <a href="file:///usr/include/c++/4.5/ext/new_allocator.h:95" >/usr/include/c++/4.5/ext/new_allocator.h:95</a>
3: std::_Vector_base<float, std::allocator<float> >::_M_deallocate(float*, unsigned long) in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:146" >/usr/include/c++/4.5/bits/stl_vector.h:146</a>
4: std::_Vector_base<float, std::allocator<float> >::~_Vector_base() in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:132" >/usr/include/c++/4.5/bits/stl_vector.h:132</a>
5: std::vector<float, std::allocator<float> >::~vector() in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:314" >/usr/include/c++/4.5/bits/stl_vector.h:314</a>
6: Matrix::~Matrix() in <a href="file:///home/leif/MarbleMachine/core/matrix.h:6" >core/matrix.h:6</a>
如果只是某种索引超出范围错误,这似乎不太可能,据我所知,向量对象主要是指向数组在内存中位置的指针(好吧,还有其他东西,但我想要的一点是make 的问题是,向量对象本身(析构函数的存储位置)似乎不太可能在内存中与实际数组的存储位置连续。此外,最重要的是,为什么析构函数会在完整的情况下占用内存。是为了释放对象使用的内存,这不会造成内存泄漏吗?顺便说一句,矩阵类没有显式析构函数,因此仅使用隐式析构函数。
最后,我知道 valgrind 中以前的错误 。可能会导致未来的错误,但之前唯一的错误是无效的读取大小和在现有库(OpenGL 和 SDL)中使用未启动的变量,因此,我发现它们极不可能在发生这种情况之前导致堆损坏,
谢谢 。 。
I have a simple matrix class I've made for use with opengl (es 2.0, afaik there isn't any built in version for that particular version of opengl).
It is basically nothing more than a vector which is resized to contain 16 floats in the constructor, (I chose a vector over just a 16 float array for the = operator it had), and some convenience functions that are useful in the context of opengl. Anyway, one of these convenience structures loads the identity matrix into the vector, it is:
void Matrix::loadIdentity()
{
matrix.resize(16, 0);
for(int i = 0; i < 16; i++)
matrix[i] = 0.0f;
for(int i = 0; i < 4; i++) {
matrix[i * 4 + i] = 1.0f;
}
}
Where matrix is:
std::vector<float>
The line that says:
matrix.resize(16, 0);
is there to make sure that the size is actually 16 floats, although it's also done in the constructor, and I don't believe it will be needed ultimately, but right now to remove one possible bug, to make life easier for debugging.
Valgrind is telling me that this function, in particular this line:
matrix[i] = 0.0f;
is causing an invalid write size of 4, which sounds suspiciously like I'm somehow calling matrix[16] = 0.0f;. However, i should only go from 0 to 15. One interesting thing to note though is that valgrind also says that the memory in question that's getting written to, was allocated by the destructor of the matrix, and more specifically, the destructor of the vector.
Address 0x150f8280 is 0 bytes inside a block of size 64 free'd 1: operator delete(void*) in /build/buildd/valgrind-3.6.1/coregrind/m_replacemalloc/vg_replace_malloc.c:387
2: __gnu_cxx::new_allocator<float>::deallocate(float*, unsigned long) in <a href="file:///usr/include/c++/4.5/ext/new_allocator.h:95" >/usr/include/c++/4.5/ext/new_allocator.h:95</a>
3: std::_Vector_base<float, std::allocator<float> >::_M_deallocate(float*, unsigned long) in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:146" >/usr/include/c++/4.5/bits/stl_vector.h:146</a>
4: std::_Vector_base<float, std::allocator<float> >::~_Vector_base() in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:132" >/usr/include/c++/4.5/bits/stl_vector.h:132</a>
5: std::vector<float, std::allocator<float> >::~vector() in <a href="file:///usr/include/c++/4.5/bits/stl_vector.h:314" >/usr/include/c++/4.5/bits/stl_vector.h:314</a>
6: Matrix::~Matrix() in <a href="file:///home/leif/MarbleMachine/core/matrix.h:6" >core/matrix.h:6</a>
This seems unlikely if it's just some sort of index out of range error, seeing as, afaik, a vector object is primarily a pointer to where the array is in memory (well, there's other stuff too, but the point I'm trying to make is that the vector object itself (where the destructor would be stored), seems unlikely that it would be contiguous in memory with where the actual array is stored. Also, on top of that, why would a destructor claim memory when it's whole point is to free up the memory an object uses, wouldn't that just create a memory leak? By the way, the matrix class doesn't have an explicit destructor, so just the implicit one is used.
Finally, I know that previous errors in valgrind can cause future errors, but the only previous errors is invalid read size and use of uninitiated variables inside of existing libraries (OpenGL and SDL), as such, I find it extremely unlikely that they are causing a heap corruption before this happens.
Thank you.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从您发布的 Valgrind 报告片段中可以清楚地看出您正在访问向量的悬空存储。
如果一个线程正在迭代向量,而另一个线程已调整向量的大小,则很容易出现此类访问。例如,这是不安全的:
在另一个线程中:
如果您有可以调整向量大小的变异器,那么您必须相对于它们序列化所有读取器,例如
在另一个线程中:
您在答案中描述的内容:
1 个图形线程
matrix.end()
超出锁定范围[这已经是一个问题了]。...
6 图形线程锁
7 图形线程获取
matrix.begin()
并开始迭代似乎与Valgrind错误报告不一致,因为它会导致访问超出数组末尾,而Valgrind报告访问在(现已删除/悬空数组)的开头。
底线:调用
begin()
、end()
和迭代都必须发生在保护容器的锁内;否则你的程序行为将是未定义的。It's pretty clear from the snippet of Valgrind report you posted that you are accessing dangling storage for a vector.
Such access could easily arise if one thread is iterating over a vector, while another thread has resized it. For example, this is unsafe:
while in another thread:
If you have mutators that can resize the vector, then you must serialize all readers with respect to them, e.g.
In another thread:
What you've described in your answer:
1 Graphics thread gets
matrix.end()
outside of lock [which is already a problem]....
6 Graphics thread locks
7 Graphics thread gets
matrix.begin()
and starts iteratingappears to not be consistent with Valgrind error report, because it would have resulted in access past the end of the array, whereas Valgrind reports access at the beginning of the (now deleted/dangling array).
Bottom line: calling
begin()
,end()
, and iteration must all happen within a lock that protects the container; otherwise your program behavior will be undefined.谢谢你的帮助,我想我终于明白了。事实上,我没有给你足够的信息来解决这个问题,所以在我给你我找到的解决方案之前,让我给你一些更多的信息。
该应用程序是一个多线程应用程序,在每个线程中,它都有一个部分迭代对象循环(相同的对象),其中包含矩阵。一种情况是物理引擎,另一种情况是渲染对象。我确实在适当的时候锁定了两个线程中的数据,但事实证明我在锁定之前就得到了迭代器的结尾。
所以我相信发生的事情是这样的:
谢谢大家的帮助。
Thank you for the help, I think I finally figured it out. It actually turns out I didn't give you enough information to solve the problem, so before I give you the solution I found, let me give you some more information.
The app was a multi-threaded app, in each thread, it has a portion where it iterates over a loop of objects (the same objects), which contain the matrix in it. In one case a physics engine, and the other, rendering the objects. I did lock the data in both threads when appropriate, but it turns out that I got the end of the iterator before the lock.
So what I believe was happening was this:
THank you everyone for your help.