【发布时间】:2019-03-24 11:48:58
【问题描述】:
当我尝试运行使用 g++ 和优化 -O2 构建的程序时,这是一种奇怪的行为。 使用:
- g++-7 (Ubuntu 7.3.0-16ubuntu3) 7.3.0
- 内核 4.15.0-36-generic
我有两个成员的结构:
struct A {
uint8_t m8;
Int128 m128;
};
Int128 在哪里:
// #pragma pack(push, 1)
struct Base128 {
__int128_t v{0};
};
// #pragma pack(pop)
#pragma pack(push, 1)
struct Int128: Base128 {
Int128();
};
#pragma pack(pop)
Base128 显式未打包,但 Int128 与对齐 1 打包
请注意,Base128 具有显式成员初始化,Int128 在另一个翻译单元具有手动定义的空主体构造函数(用于避免内联)。
当我将Base128 包装更改为与Int128 相同时,程序不会崩溃。
似乎编译器生成了无效指令:MOVAPS 而不是MOVUPS 用于访问构造函数中的__int128_t 成员:
00000000000006b0 <_ZN6Int128C1Ev>:
6b0: 66 0f ef c0 pxor %xmm0,%xmm0
6b4: 55 push %rbp
6b5: 48 89 e5 mov %rsp,%rbp
6b8: 0f 29 07 movaps %xmm0,(%rdi)
6bb: 5d pop %rbp
6bc: c3 retq
6bd: 0f 1f 00 nopl (%rax)
反之亦然:
00000000000006b0 <_ZN6Int128C1Ev>:
6b0: 66 0f ef c0 pxor %xmm0,%xmm0
6b4: 55 push %rbp
6b5: 48 89 e5 mov %rsp,%rbp
6b8: 0f 11 07 movups %xmm0,(%rdi)
6bb: 5d pop %rbp
6bc: c3 retq
6bd: 0f 1f 00 nopl (%rax)
你有什么想法:我做错了什么?
源代码:
test.h:
#pragma once
#include <cstdint>
//#pragma pack(push, 1) // it fixes problem
struct Base128 {
__int128_t v{0};
};
//#pragma pack(pop)
#pragma pack(push, 1)
struct Int128: Base128 {
Int128();
};
#pragma pack(pop)
struct A {
uint8_t m8;
//Int128 __attribute__((aligned(16))) m128; // it fixes problem
Int128 m128;
};
test.cpp:
#include "test.h"
// Int128::Int128() : Base128{0} {} // Fixes (why ?!)
Int128::Int128() {}
main.cpp:
#include "test.h"
int main() {
A a;
return 0;
}
构建和运行:
g++-7 --save-temps -Wall -Wextra -std=c++14 -O2 -g main.cpp test.cpp && ./a.out
Source code on gitlab is here。它可以如下构建和运行:
./build.sh # build and run (crashes)
./build.sh [1..5] # where 1..5 -- different fixes
【问题讨论】:
-
我没有查看详细信息,但
#pragma pack(push, 1)看起来很可疑。请在问题中提供minimal reproducible example(强调最小),而不是通过外部链接。 -
您能否编辑掉代码中的
#ifdefs,以便我们只看到失败的测试版本?这很难按原样遵循。 -
谢谢你,我已经修正了你的笔记
-
我的直觉告诉我这是一个编译器错误,但我必须说,从对齐的结构中继承明确未对齐的结构有点导致灾难,如果在这两种类型的指针之间如何执行强制转换不存在根本不可调和的冲突,我也不会感到惊讶。也许错误是首先编译成功...
-
是的...考虑以下内容:gcc.godbolt.org/z/ZV_Ya1。
foo()显然是按照应有的方式实现的,但是bar()会以与您正在经历的完全相同的方式导致灾难。
标签: c++ gcc segmentation-fault g++ memory-alignment