C++强制转换不同声明或类型的函数指针隐患

时间:2022-11-04 18:56:45

之前碰到一个问题,没有注意看函数指针的定义。造成一个错误,写到这里给自己一个提醒。也给大家看看我这个不小心的人犯的错误。嘿嘿!

先看段测试代码:

void test( int param )

{

     int ret = 0;

     for ( int i = 0; i < param; ++i )

     {

      ret += i;

     }

     ret >>= 16;

     ret |= ( ret << 16 );

}

typedef bool ( *PFUNC )( int args );

int main( void )

{

     PFUNC Func;

     Func = ( PFUNC )test;

     if ( Func( 200 ) )

    {

         cout << "good" << endl;

    }

    else

     {

          cout << "bad" << endl;

     }

     return 0;

}

这段代码里面,我故意把test函数里面的内容多写几步,让它有“效果”。在游戏程序里面,一个函数可能有很多的语句,这里只是简单演示下我的错误- -。 我们的函数指针声明是:

typedef bool ( *PFUNC )( int args );

它指向的是返回值为bool,参数为int类型的函数。而我定义的test函数是没有返回值的。来看看程序输出会是什么。

这里可以说,输出的结果是未知的。因为不知道Func( 200 )的返回值是多少。可能有的朋友会疑问,这里的test函数不是没有返回值吗?

这里就要牵涉到汇编层面我们的返回值如果是在32位以内的话,都会放到eax里面。我们没有返回值,而通过强制类型转换。这里能通过编译了。但是在test函数结束时,eax寄存器里面的值是不确定的。当我们判断

if ( Func( 200 ) )这个条件也就是不确定的。在游戏程序中,这样的错误是不允许的。也可以说是严重的。

可能也有朋友会问为什么EAX的值是不确定的呢? 因为eax是通用寄存器,在函数内部,它通常用来保存一些临时值。所以改变的因素就很大。不确定性也就很大。

看看test的调试版本反汇编代码:

test:

004170B0  push        ebp 

004170B1  mov         ebp,esp

004170B3  sub         esp,0D8h

004170B9  push        ebx 

004170BA  push        esi 

004170BB  push        edi 

004170BC  lea         edi,[ebp-0D8h]

004170C2  mov         ecx,36h

004170C7  mov         eax,0CCCCCCCCh

004170CC  rep stos    dword ptr [edi]

004170CE  mov         dword ptr [ret],0

004170D5  mov         dword ptr [i],0

004170DC  jmp         test+37h (4170E7h)

004170DE  mov         eax,dword ptr [i]

004170E1  add         eax,1

004170E4  mov         dword ptr [i],eax

004170E7  mov         eax,dword ptr [i]

004170EA  cmp         eax,dword ptr [param]

004170ED  jge         test+4Ah (4170FAh)

004170EF  mov         eax,dword ptr [ret]

004170F2  add         eax,dword ptr [i]

004170F5  mov         dword ptr [ret],eax

004170F8  jmp         test+2Eh (4170DEh)

004170FA  mov         eax,dword ptr [ret]

004170FD  sar         eax,10h

00417100  mov         dword ptr [ret],eax

00417103  mov         eax,dword ptr [ret]

00417106  shl         eax,10h

00417109  or          eax,dword ptr [ret]

0041710C  mov         dword ptr [ret],eax

0041710F  pop         edi 

00417110  pop         esi 

00417111  pop         ebx 

00417112  mov         esp,ebp

00417114  pop         ebp 

00417115  ret    

改变eax的地方我已经标注为红色,我们能准确知道最后改变后的eax的值吗? 主函数里面还等着这个eax的值呢 - -

答案是不能,况且在复杂的游戏服务器程序中。这里只是单是返回值不同。还有参数不同的强制类型转换,参数和返回值都不同的强制类型转换。这种不小心的操作,很可能导致程序越界,溢出等而崩溃。