【发布时间】:2017-10-30 14:01:54
【问题描述】:
我怀疑我发现了一个 g++ 优化错误,该错误与取消引用具有负索引的对象(结构)中的数组有关。
在下面,节点是一个结构,它有一个数组前面它(在我的真实代码中,它是一个跳过列表的节点,它的指针数量和数据包的大小都是变量和底层 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-aggressive-loop-optimizations 似乎可以修复它,但如果输出代码正确显然会更好。
我把它放在这里是为了 (a) 验证这是一个错误,因为我是这里的新手,这是我的第一个问题,(b) 询问 gcc 开发社区中的任何知识渊博的人该怎么做(例如,我应该如何报告它,以及它是否已在以后的版本中修复),以及 (c) 允许在 CentOS 7(或任何其他 4.8 发行版)上经历过这个最令人沮丧和耗时的问题的人查看确认他们遇到了来自其他患者的错误!
【问题讨论】:
-
对(C 风格)数组使用负索引不是一种未定义的行为吗?
-
不,
arr[n]被定义为*(arr+n)用于所有 n(正数和负数)。当然,要确保引用是正确分配的内存,这取决于实现。见this question -
this question 可能有您想要的答案。
-
只是普通索引超出范围,它是 UB。数组被声明为具有
1的大小,因此除 [0] 之外的任何数组索引都是未定义的行为。我怀疑您可能试图将已定义的C行为与未定义的C++行为混合在一起。请参阅en.cppreference.com/w/cpp/language/ub中的越界访问 -
@RichardCritten 请将此评论作为答案。
标签: c++ arrays loops optimization g++