我怀疑我发现了一个g++优化错误,它与带有负索引的对象(structs)中的取消引用数组有关。
在下面的结构中,Node是在它前面有一个数组的结构(在我的实际代码中,它是一个Skip列表的节点,它的指针数量和数据包大小都是可变的,并且对底层的SkipList代码来说是未知的,因此决定将指针放在对象引用之前,而数据包放在对象之后很长时间)。
#include <iostream>
#include <stdlib.h>
class Node {
public:
unsigned int ptr[1]; // really an array going backwards
long datum; // This seems to be necessary for the bug to surface
};
class NodeList {
public:
Node* hdr;
NodeList() {
void* p_v = malloc( sizeof(Node) + 32 * sizeof( unsigned int ) );
hdr = (Node*)((char*)p_v + 32 * sizeof(unsigned int));
hdr->ptr[-5]=100;
}
void setNodes() {
int nn=0;
while( rand() > 20 && nn<9 ) {
nn++;
}
if( nn < 9 ) {
nn = 9;
}
// It is a logical truth that nn = 9 here
//nn = 9; // IF THIS IS UNCOMMENTED EVERYTHING WORKS!
std::cout << "nn=" << nn << " (should be 9) " << std::endl;
int ctr = 0;
for( int i=0; i<=nn; i++ ) {
ctr++;
hdr->ptr[-i]=0;
}
std::cout << "ctr was incremented " << ctr << " times (should be 10) and hdr->ptr[-5] = " << hdr->ptr[-5] << " (should be 0)\n";
}
};
int main( int argc, char** argv ) {
NodeList list;
list.setNodes();
}预期输出ctr增加10倍,hdr->ptr-5为0.优化后的代码只需要循环一次(即不循环),并将ptr->hdr-5保留为100。这是个窃听器。
-fno-咄咄逼人的循环优化似乎修复了它,但如果输出代码是正确的,显然会更好。
我把这个放在这里是为了(a)确认这是一个bug,因为我是这里的新手,这是我的第一个问题,(b)问任何熟悉gcc开发社区的人,该做些什么。我应该如何报告它,以及它是否在以后的版本中被修复),和(c)允许那些在CentOS 7上经历过这个最令人沮丧和耗费时间的问题的人(或任何其他版本,4.8)看到他们已经从同病者那里感染了一个bug!
发布于 2017-05-30 08:35:13
在这里,对于“数组”的含义,我们必须小心。数组是任何定义为
some_type arr[number];但不是像
some_type*ptr = some_address;负指数与正指数没有什么不同,ptr[n]被解释为*(ptr+n) (您甚至可以在C中使用n[ptr] )。因此,在索引时,使用指针算法。
无论如何实现,在C和C++中访问数组边界外的元素都是未定义的行为(UB)。例如
some_type arr[10];
some_type*ptr = arr+5;
some_type foo = ptr[-4]; // ok, access to arr[1]
some_type bar = ptr[-6]; // UB, out-of-bound access
some_type val = arr[-1]; // UB, out-of-bound accesshttps://stackoverflow.com/questions/44256413
复制相似问题