编译器在构造函数中计算的成员偏移量不正确
Incorrect member offset calculated by compiler in constructor
VC++ 编译器出于未知原因在构造函数中为具有以下结构的 class 生成不正确的成员偏移量:
class AlignTest
{
public:
enum TEnum : char
{
one,
two
};
protected:
int& ref;
char c;
size_t keyVar;
public:
AlignTest(int& x. size_t other = 0) : ref(x)
{
c = 1;
keyVar = other;
}
void Print();
};
由于未知原因,在构造函数执行期间,keyVar 赋值写入地址 this+0x09,但由于对齐,keyVar 实际上位于 this+0x10。令人惊讶的是,当 运行 Print 方法时,代码会正确生成并将 keyVar 解析为 this+0x10。
少量观察:
- 在keyVar中加入alignof(8)即可解决问题
- 将构造函数的定义移动到 cpp 文件解决了问题
- 在 header
中使用初始化列表时出现同样的问题
- 无法在较新的编译器上的不同项目中重现简化版本(正在处理)
- 检查 headers 是否在定义构造函数时 class 中使用的每个类型都是众所周知的。
- 运行调试,关闭优化,x64,工具集:windowsapplicationfordrivers10.0,VS2017。
构造函数代码似乎没有考虑 keyVar 对齐。是否有一些 standard/compiler 限制,或者它只是编译器 bug/side 的影响?
用 VS 的一段反汇编代码更新,注意与 "this" 地址的偏移量。
在 .h 文件的构造函数中:
keyVar = other;
00007FF76C32D4DB 48 8B 44 24 08 mov rax,qword ptr [this]
00007FF76C32D4E0 48 8B 4C 24 18 mov rcx,qword ptr [other]
00007FF76C32D4E5 48 89 48 09 mov qword ptr [rax+9],rcx
在 Print 方法中:
size_t tmp2 = keyVar;
00007FF76C3918D0 48 8B 84 24 40 02 00 00 mov rax,qword ptr [this]
00007FF76C3918D8 48 8B 40 10 mov rax,qword ptr [rax+10h]
00007FF76C3918DC 48 89 44 24 68 mov qword ptr [rsp+68h],rax
更新
原来的项目好像有问题。我已将可疑 classes 移至单独的项目,使用相同的编译工具但无法重现。
周一将以另一种方式开始——从原来的项目中删除一些东西,看看会有什么不同。
正如 Igor Tandetnik 所建议的那样,问题出在带有构造函数 (1) 的编译单元和带有打印方法 (8) 的单元中的不同包级别。在项目的 header.
之一中发现未还原 pack(1) 指令
VC++ 编译器出于未知原因在构造函数中为具有以下结构的 class 生成不正确的成员偏移量:
class AlignTest
{
public:
enum TEnum : char
{
one,
two
};
protected:
int& ref;
char c;
size_t keyVar;
public:
AlignTest(int& x. size_t other = 0) : ref(x)
{
c = 1;
keyVar = other;
}
void Print();
};
由于未知原因,在构造函数执行期间,keyVar 赋值写入地址 this+0x09,但由于对齐,keyVar 实际上位于 this+0x10。令人惊讶的是,当 运行 Print 方法时,代码会正确生成并将 keyVar 解析为 this+0x10。
少量观察:
- 在keyVar中加入alignof(8)即可解决问题
- 将构造函数的定义移动到 cpp 文件解决了问题
- 在 header 中使用初始化列表时出现同样的问题
- 无法在较新的编译器上的不同项目中重现简化版本(正在处理)
- 检查 headers 是否在定义构造函数时 class 中使用的每个类型都是众所周知的。
- 运行调试,关闭优化,x64,工具集:windowsapplicationfordrivers10.0,VS2017。
构造函数代码似乎没有考虑 keyVar 对齐。是否有一些 standard/compiler 限制,或者它只是编译器 bug/side 的影响?
用 VS 的一段反汇编代码更新,注意与 "this" 地址的偏移量。
在 .h 文件的构造函数中:
keyVar = other;
00007FF76C32D4DB 48 8B 44 24 08 mov rax,qword ptr [this]
00007FF76C32D4E0 48 8B 4C 24 18 mov rcx,qword ptr [other]
00007FF76C32D4E5 48 89 48 09 mov qword ptr [rax+9],rcx
在 Print 方法中:
size_t tmp2 = keyVar;
00007FF76C3918D0 48 8B 84 24 40 02 00 00 mov rax,qword ptr [this]
00007FF76C3918D8 48 8B 40 10 mov rax,qword ptr [rax+10h]
00007FF76C3918DC 48 89 44 24 68 mov qword ptr [rsp+68h],rax
更新
原来的项目好像有问题。我已将可疑 classes 移至单独的项目,使用相同的编译工具但无法重现。
周一将以另一种方式开始——从原来的项目中删除一些东西,看看会有什么不同。
正如 Igor Tandetnik 所建议的那样,问题出在带有构造函数 (1) 的编译单元和带有打印方法 (8) 的单元中的不同包级别。在项目的 header.
之一中发现未还原 pack(1) 指令