<分区>
我只花了半天时间来解决 x86-64 代码中的一个微妙崩溃,所以这对其他人来说是一个提醒 - 我没有在其他地方看到过这个问题。
如果您在没有正确声明的情况下使用 libc 函数,gcc 将假定它返回 int。例如。 setlocale() 被假定为 int setlocale(),在 EAX 中返回一个 32 位 int 值。
尝试通过隐式或显式转换将此返回值转换为指针,将强制通过符号扩展从 32 位转换为 64 位,即使被调用函数在 RAX 中返回了有效的 64 位指针值!例如
char *p = setlocale(0, 0); // bear with me for a second
被编译成
1c: b8 00 00 00 00 mov $0x0,%eax
21: e8 00 00 00 00 callq 26 <hard_locale+0x26>
26: 48 98 cltq ; <--- eax is expanded in rax
GCC 甚至试图告诉您:
warning: initialization makes pointer from integer without a cast
如果您添加显式强制转换,警告将更改为,这表明了问题:
warning: cast to pointer from integer of different size
如果运气好的话,什么都没有发生,但是如果恰好返回了一个很大的内存中up指针的值,那就乱七八糟了,如下:
function returns in RAX: 0x07ffff7b9705e
cltq considers EAX with negative sign: 0xf7b9705e
now RAX is: 0xfffffffff7b9705e
并且您的指针无效。
修复和解决方案:
始终使用正确的函数声明
-Wall -Werror 应该在 x86-64 编译器中默认打开。