【发布时间】:2021-08-13 12:06:08
【问题描述】:
// Compiled with GCC 7.3.0, x86-64 -g -O3 -std=gnu++11
// Tested on OS (1) Ubuntu 18.04 LTS, (2) Gentoo
int Listen(... socket)
{
char buffer[INT16_MAX];
. . .
. . . = recvfrom(socket, buffer, ....)
ParseMsg(buffer)
}
void ParseMsg(uint8_t *const msg)
{
. . .
uint16_t* word_arr = (uint16_t*)(msg+15); // if I changed 15 to 16 (aligned to uint16_t)
// the program doesn't crash
for(size_t i = 0 ; i < 30 ; ++i)
{
word_arr[i] = 1; // after some iterations (around 13) the program crashes with segmentation fault
// if i add a print statement inside the loop the program doesn't crash
}
// word_arr[20] = 1; // if I assign value not in loop the program doesn't crash
}
我找到了一些讨论这个问题的链接:
https://github.com/samtools/htslib/issues/400
https://github.com/xianyi/OpenBLAS/issues/1137
但他们用处理器术语说话。有人可以确认这个错误存在吗?
附言
我使用 -O2 优化标志运行代码。没有崩溃
【问题讨论】:
-
您应该在调试器中查看失败的指令。很可能是向量指令。硬件是否通常接受该大小的未对齐读取并不重要,如果 C++ 标准规定未对齐读取是非法的,编译器可以使用该信息进行优化。
-
这不是优化器中的错误,而是您的代码中的问题。根据 C++ 标准,未对齐访问具有未定义的行为。
-
由于严格的别名规则,您的代码格式错误。请参阅最近的问题stackoverflow.com/a/67636420/12939557 和著名的问题stackoverflow.com/questions/98650/…。
-
@JérômeRichard 这里有点复杂。字符指针(包括
signed char和unsigned char)被明确排除在严格别名规则之外,并且在大多数实现中,uint8_t是来自unsigned char的 typdef,因此不适用严格别名规则。 -
@Johan 确实!我对
uint8_t类型感到困惑。我的错。无论如何,解决此问题的解决方案看起来与类型双关问题相同:使用memcpy(或 C++20 中的bitcast,或 C 中的联合)。
标签: gcc optimization segmentation-fault compiler-optimization memory-alignment