2014年6月15日 星期日

c 整數的 overflow 和 loop

這個程式碼有什麼問題呢?

il.c
 1 #include <stdio.h>
 2 
 3 int main()
 4 {
 5   unsigned int SIZE = 5000000000;
 6   int i = 0;
 7   for(i = 0; i <= SIZE; i++) 
 8   {
 9     //printf("%d\n", i);
10   }
11   printf("%x\n", SIZE);
12   printf("%x\n", i);
13   printf("exit\n");
14   return 0;
15 }

組合語言之前沒有秘密, 翻成組合語言大概如下:

il.s
 1  .file "il.c"
 2  .section .rodata
 3 .LC0:
 4  .string "%d\n"
 5  .text
 6  .globl main
 7  .type main, @function
 8 main:
 9 .LFB0:
10  .cfi_startproc
11  pushl %ebp
12  .cfi_def_cfa_offset 8
13  .cfi_offset 5, -8
14  movl %esp, %ebp
15  .cfi_def_cfa_register 5
16  andl $-16, %esp
17  subl $32, %esp
18  movl $705032704, 24(%esp)
19  movl $0, 28(%esp)
20  movl $0, 28(%esp)
21  jmp .L2
22 .L3:
23  movl 28(%esp), %eax
24  movl %eax, 4(%esp)
25  movl $.LC0, (%esp)
26  call printf
27  addl $1, 28(%esp)
28 .L2:
29  movl 28(%esp), %eax
30  cmpl 24(%esp), %eax
31  jb .L3
32  leave
33  .cfi_restore 5
34  .cfi_def_cfa 4, 4
35  ret
36  .cfi_endproc
37 .LFE0:
38  .size main, .-main
39  .ident "GCC: (Debian 4.8.2-16) 4.8.2"
40  .section .note.GNU-stack,"",@progbits

il.s L18 705032704 是怎麼來的, 5000000000 怎麼不見了, 5000000000=0x12A05F200
705032704 = 0x  2A05F200
有點感覺了嗎?
5000000000 超過 unsigned int (4 byte) 的大小, gcc 只留下了右邊 4 byte, 這是 undefined 行為, gcc 是如此處理 overflow。

再來是 il.c L7 的 signed int 和 unsigned int 的比較會提升為 unsigned int 和 unsigned int 的比較, 從 il.s L31 也可看出。

JB Jump if below unsigned
ref: http://www.unixwiz.net/techtips/x86-jumps.html
jb 是以 unsigned 的方式來比較兩個數字。

0xffffffff = 4294967295
0x7fffffff = 2147483647

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。