游戏开发论坛

 找回密码
 立即注册
搜索
查看: 6200|回复: 18

发现VC++ 6.0的BUG,很有趣

[复制链接]

96

主题

529

帖子

539

积分

高级会员

Rank: 4

积分
539
发表于 2005-6-14 19:11:00 | 显示全部楼层 |阅读模式
测试函数仅5行:
BOOL Test()
{
  BOOL ret = FALSE;
  for(unsigned long i = 1; i >= 0; --i)
  {
  }
  return ret;
}

VC++ 6.0编译,调用到该测试函数,则进入死循环,注释掉循环的三行,或者将函数改成:
BOOL Test()
{
  BOOL ret = FALSE;
  for(unsigned long i = 2; i >= 1; --i)
  {
  }
  return ret;
}
程序正常运行!

注意:调用Test函数时不要接受返回值:
比如:
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        // TODO: Place code here.
        Test();
        return 0;
}
不要写成
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        // TODO: Place code here.
        BOOL ret = Test();
        return 0;
}
就可以达到死循环.
用反汇编软件反汇编后发现,这些代码被VC错误优化成了
401000: jmp 401000
所以就造成了死循环现象

30

主题

298

帖子

299

积分

中级会员

Rank: 3Rank: 3

积分
299
QQ
发表于 2005-6-14 20:04:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

我看着怎么像是无符号整数下溢的说?

96

主题

529

帖子

539

积分

高级会员

Rank: 4

积分
539
 楼主| 发表于 2005-6-14 20:17:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

如果是滥出,为什么程序不出错,只是死循环.再说了,代码中哪里有滥出的机会?
最有力的说明是反汇编代码401000: jmp 400100,这一行代码就足以说明了这一点.上面代码要用release的fast优化编译方式,而不能用debug的常规编译方式,因为debug不进行代码优化,所以自然不会出现优化错误.

为什么会产生这种情况,我想是优化造成的,有点反汇编基础的人都知道,没有任何代码的空循环是不会被编译的,而会被忽略,被赋一次值就没再改变的变量(上面代码中的ret = FALSE;return ret),是会直接return FALSE代替的.

BOOL Test()
{
  BOOL ret = FALSE;
  for(unsigned long i = 1; i >= 0; --i)
  {
  }
  return ret;
}
编译器第一步优化:判断循环没有任何用处,可以忽略编译.
编译器第二步优化:判断ret没有任何改变值的机会,用return FALSE代替.
编译器第三步优化:判断ret和i在函数返回前的最终值一定相等,都等于0.所以用同一个寄存器来表示两个变量
所以到第三步优化时,已经出现优化絮乱,代码成了:
BOOL Test()
{
register BOOL ret = FALSE;
unsigned int &i = ret;
for(;i>=0;)
{
}
return FALSE;
}
}
再经过第四步优化,判断该函数是个死循环.所以直接用jmp xxxx跳回本位代码代替.
优化错误,但优化得相当厉害,jmp xxxx一行代码就代替了以下所有的代码:

BOOL Test()
{
  BOOL ret = FALSE;
  for(unsigned long i = 1; i >= 0; --i)
  {
  }
  return ret;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
        // TODO: Place code here.
        Test();
        return 0;
}

96

主题

529

帖子

539

积分

高级会员

Rank: 4

积分
539
 楼主| 发表于 2005-6-14 20:33:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

这也很合理地解释了为什么
for(unsigned long i = 1; i >= 0; --i)
  {
  }
改成
for(unsigned long i = 2; i >= 1; --i)
  {
  }
就不会再出现程序死锁的现象.

因为造成优化絮乱的第三步优化条件不再成立:

编译器第三步优化:判断ret和i在函数返回前的最终值一定相等,都等于0.所以用同一个寄存器来表示两个变量

3

主题

155

帖子

161

积分

注册会员

Rank: 2

积分
161
发表于 2005-6-14 22:37:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

unsigned long i=1;
i==0x00000001;
i--;
i==0x00000000;
i--;
i==0xffffffff;

编译器看见是无符号型,而无符号型必定>=0;很快可以决定.....401000: jmp 400100

4

主题

118

帖子

119

积分

注册会员

Rank: 2

积分
119
发表于 2005-6-15 13:35:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

是无符号造成的吧
楼上的是正解

62

主题

331

帖子

366

积分

中级会员

Rank: 3Rank: 3

积分
366
QQ
发表于 2005-6-15 14:11:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

bug不是那么好找的吖

..

36

主题

382

帖子

498

积分

中级会员

Rank: 3Rank: 3

积分
498
发表于 2005-6-15 16:37:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

无符号的问题,不是6.0 de bug
是作者的bug,haha

14

主题

245

帖子

256

积分

中级会员

Rank: 3Rank: 3

积分
256
QQ
发表于 2005-6-16 09:40:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

看到标题,我还真以为是个Bug。。!
看到内容,哎!

95

主题

1089

帖子

3301

积分

论坛元老

Rank: 8Rank: 8

积分
3301
QQ
发表于 2005-6-16 12:31:00 | 显示全部楼层

Re:发现VC++ 6.0的BUG,很有趣

什么BUG阿!
for(unsigned long i = 1; i >= 0; --i)
i 一定是〉=0的啦,0-1肯定 〉=0,
哈哈,阿笨。。。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-26 02:17

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表