在之前写一个代码的过程中,没有注意细节,对于一个文件的大小,就默认定义为unsigned int类型了,然后,每次遍历一段之后,就减去遍历的长度,这个unsigned int类型的值,在正常的测试下,并没有出现什么问题,但是到了真正的压力测试,大量的fuzzer来进行测试的时候,出现了一个看起来很奇怪的bug,正数居然比负数小?这是什么原因?我们看看下面的代码:
int v1 = -1; unsigned int v2 = 5; if (v2 < v1) { printf("error\n"); } else { printf("rigth\n"); }
按照我们的思路,该代码输出的肯定是right,因为很明显5比-1要大。但是最终输出的结果是:
说明在比较的时候,确实-1大于了5?为什么会这样呢?接下来我们来看一段汇编:
int v1 = -1; 00A5180E mov dword ptr [v1],0FFFFFFFFh unsigned int v2 = 5; 00A51815 mov dword ptr [v2],5 if (v2 < v1) 00A5181C mov eax,dword ptr [v2] 00A5181F cmp eax,dword ptr [v1] 00A51822 jae main+43h (0A51833h) { printf("error\n"); 00A51824 push offset string "error\n" (0A56B30h) 00A51829 call _printf (0A51320h) 00A5182E add esp,4 } else 00A51831 jmp main+50h (0A51840h) { printf("rigth\n"); 00A51833 push offset string "rigth\n" (0A56B38h) 00A51838 call _printf (0A51320h) 00A5183D add esp,4 }
这段汇编代码中我认为最重要的是:
大家注意看这条指令jae,这条汇编跳转指令比较的是两个无符号整数的值,如果我们的-1被当作一个无符号的数,那么它比5大,那也就不足为奇了。
接下来看看如果是用两个int型的变量,会有什么结果?
int v4 = -1; int v3 = 5; if (v3 < v4) { printf("error\n"); } else { printf("rigth\n"); }
结果是rigth,也就是我们期盼的结果,那么我们再来看看汇编:
int v4 = -1; 00DC180E mov dword ptr [v4],0FFFFFFFFh int v3 = 5; 00DC1815 mov dword ptr [v3],5 if (v3 < v4) 00DC181C mov eax,dword ptr [v3] 00DC181F cmp eax,dword ptr [v4] 00DC1822 jge main+43h (0DC1833h) { printf("error\n"); 00DC1824 push offset string "error\n" (0DC6B30h) 00DC1829 call _printf (0DC1320h) 00DC182E add esp,4 } else 00DC1831 jmp main+50h (0DC1840h) { printf("rigth\n"); 00DC1833 push offset string "rigth\n" (0DC6B38h) 00DC1838 call _printf (0DC1320h) 00DC183D add esp,4 }
这段汇编代码中使用的jpe汇编,是比较两个有符号整数的跳转指令:
所以我们就得到了想要的正确结果。
在写代码的过程中,要切记在表达式中混用带符号和不带符号数,因为当不带符号的数和一个带符号的负数比较时,负数会发生位拓展。
“怅寥廓,问苍茫大地,谁主沉浮?”