在项目中遇到一个奇怪的宕机问题,后来查询定位发现是erlang底层数据溢出问题,用c模拟情况类似,当一个int类型的x值大于等于1<<25的时候,再左移6位会造成nt溢出,然后再强转成64位无符号整数。
test_int.c
#include <stdio.h>
int main(){
int a = 1;
int x = (a<<25);
int x1 = (x<<6)+10;
unsigned long y = (unsigned long)(x1);
y+=1;
y+=1;
y+=1;
y+=1;
printf("x=%d/n", x);
printf("x1=%d/n", x1);
printf("y=%lu/n", y);
return 0;
}
输出结果
x=33554432 x1=-2147483638 y=18446744071562067982
gcc -S test_int.c
subq $32, %rsp
movl $1, -4(%rbp) --- - -4(%rbp)表示a
movl -4(%rbp), %eax
sall $25, %eax
movl %eax, -8(%rbp) ----- -8(%rbp) 表示 x
movl -8(%rbp), %eax
sall $6, %eax
addl $10, %eax
movl %eax, -12(%rbp) ---- -12(%rbp) 表示x1
movl -12(%rbp), %eax ------ 这里开始符号扩展
cltq
movq %rax, -24(%rbp)
addq $1, -24(%rbp)
addq $1, -24(%rbp)
addq $1, -24(%rbp)
addq $1, -24(%rbp)
movl -8(%rbp), %eax
movl %eax, %esi
顺带再分析了一下32位有符号数转换成64位无符号数的时候在底层汇编会发生什么。
有符号数在底层都是用补码进行表示,转换成无符号数的时候需要根据最高位进行判断,最高位是1的话则用1来扩充,是0的话用0扩充。
cltq就是符号扩展指令,只对eax寄存器扩展到rax寄存器。
原创文章,作者:6024010,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/245414.html