一次int转换成unsigned long数值溢出问题


在项目中遇到一个奇怪的宕机问题,后来查询定位发现是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/245414.html

(0)
上一篇 2022年4月18日
下一篇 2022年4月18日

相关推荐

发表回复

登录后才能评论