评论

收藏

[C++] VC6/VS2003编译器优化造成的bug

编程语言 编程语言 发布于:2021-08-03 14:25 | 阅读数:585 | 评论:0

昨天在CSDN上面看到这样一贴,居然爆料VC6/VS2003有一个严重的bug,于是自己也仔细研究一番:
1、原贴地址:
DSC0000.jpeg

2、出错代码:
// VC6/VC2003 使用/O2编译(默认的release模式), 输出结果有"impossible!!!" #include <stdio.h> int main() {     static const int T[1] = {0};     int n = 0;     for(int i = 536000000; i < 536000004; ++i)     {         if(i < 0) { printf("impossible!!!/n"); break; }         if(i >= 0 && i < 1) n += T;     }     printf("end/n");     getchar();     return n; }
3、原因分析
当我在使用IDE环境选择Release生成后,确实发现有上述问题
于是我修改他的代码,狼兄弟建议我先看看此时i的十进制数值与十六进制数值:
#include <stdio.h> int main() {     static const int T[1] = {0};     int n = 0;     for(int i = 536000000; i < 536000004; ++i)     {         if(i < 0)        {            printf("impossible is %d/t%x/n",i,i);            break;        }         if(i >= 0 && i < 1)            n += T;     }     printf("end/n");     return n; }
在命令行编译参数中添加/Fa即可得到汇编代码(当前目录中Hello.asm):
DSC0001.jpeg

TITLEHello.cpp.386Pinclude listing.incif @Version gt 510.model FLATelse_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'_TEXTENDS_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDSCONSTSEGMENT DWORD USE32 PUBLIC 'CONST'CONSTENDS_BSSSEGMENT DWORD USE32 PUBLIC 'BSS'_BSSENDS_TLSSEGMENT DWORD USE32 PUBLIC 'TLS'_TLSENDS;COMDAT ??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDS;COMDAT ??_C@_04NBKL@end?6?$AA@_DATASEGMENT DWORD USE32 PUBLIC 'DATA'_DATAENDS;COMDAT _main_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'_TEXTENDSFLATGROUP _DATA, CONST, _BSSASSUMECS: FLAT, DS: FLAT, SS: FLATendifCONSTSEGMENT_?T@?1??main@@9@4QBHB DD 00HCONSTENDSPUBLIC_mainPUBLIC??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ ; `string'PUBLIC??_C@_04NBKL@end?6?$AA@; `string'EXTRN_printf:NEAR;COMDAT ??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@; File Hello.cpp_DATASEGMENT??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ DB 'impossible is %d', 09HDB'%x', 0aH, 00H; `string'_DATAENDS;COMDAT ??_C@_04NBKL@end?6?$AA@_DATASEGMENT??_C@_04NBKL@end?6?$AA@ DB 'end', 0aH, 00H; `string'_DATAENDS;COMDAT _main_TEXTSEGMENT_mainPROC NEAR; COMDAT; File Hello.cpp; Line 4pushesi; Line 6xoresi, esi; Line 8movecx, 536000000; 1ff2b600Hmoveax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+2144000000$L581:; Line 10cmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHBjlSHORT $L595; Line 15cmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+4jgeSHORT $L582; Line 16addesi, DWORD PTR [eax]$L582:addeax, 4incecxcmpeax, OFFSET FLAT:_?T@?1??main@@9@4QBHB+2144000016jlSHORT $L581; Line 19pushOFFSET FLAT:??_C@_04NBKL@end?6?$AA@; `string'call_printfaddesp, 4; Line 20moveax, esipopesi; Line 21ret0$L595:; Line 12pushecxpushecxpushOFFSET FLAT:??_C@_0BF@LPL@impossible?5is?5?$CFd?7?$CFx?6?$AA@ ; `string'call_printfaddesp, 12; 0000000cH; Line 19pushOFFSET FLAT:??_C@_04NBKL@end?6?$AA@; `string'call_printfaddesp, 4; Line 20moveax, esipopesi; Line 21ret0_mainENDP_TEXTENDSEND
查看Release生成后在汇编代码:
00401000  push        esi  00401001  xor         esi,esi 00401003  mov         eax,800B5514h 00401008  cmp         eax,offset string L"/0" (407D14h) 0040100D  jl          main+24h (401024h) 0040100F  cmp         eax,407D18h 00401014  jge         main+18h (401018h) 00401016  add         esi,dword ptr [eax] 00401018  add         eax,4 0040101B  cmp         eax,800B5524h 00401020  jl          main+8 (401008h) 00401022  jmp         main+31h (401031h) 00401024  push        offset string "impossible!!!/n" (407104h) 00401029  call        printf (4011FEh) 0040102E  add         esp,4 00401031  push        offset string "end/n" (4070FCh) 00401036  call        printf (4011FEh) 0040103B  mov         eax,dword ptr [__iob+4 (409044h)] 00401040  add         esp,4 00401043  dec         eax  00401044  mov         dword ptr [__iob+4 (409044h)],eax 00401049  js          main+55h (401055h) 0040104B  inc         dword ptr [__iob (409040h)] 00401051  mov         eax,esi 00401053  pop         esi  00401054  ret              00401055  push        offset __iob (409040h) 0040105A  call        _filbuf (401066h) 0040105F  add         esp,4 00401062  mov         eax,esi 00401064  pop         esi  00401065  ret
可以惊奇的发现i <0会被优化成0x800B5514 <0x00407D14,于是乎让我想起前面编译器优化参数的三个选项,打开IDE的编译选项:
DSC0002.jpeg

DSC0003.jpeg

3、解决办法:
这是由于编译器参数优化造成的,具体影响结果的参数是/O2(代码速度最快),如果使用/Od(不使用优化)则不会出现上述结果,测试如下图:
DSC0004.jpeg

在此,十分感谢寂寞的狼、iceboy等友友的耐心的指导与无私的帮助!
4、相关文章:
深入探究VC —— 编译器cl.exe(1)
深入探究VC —— 编译器cl.exe(2)


关注下面的标签,发现更多相似文章