• 空指针带来的AV异常.


      故名思意, 如果一个指针是NULL, (NullPtr == NULL), 则 NullPtr->Method() 会产生异常。

      但是根据被调用函数不同, 分为  (1) NullPtr->Virtual_Method() (2) NullPtr->Member_Method()

      

       //    
        // 例子
        //
        class AA
        {
        public:
            virtual void SayHello(int dwDummy)
            {
                cout << "Hello" << endl;
            }
            void SayHello(void)
            {
                m_nValue = 0;
                cout << "Hello" << endl;
            }
        private:
            int m_nValue;
        };
        int main ( )
        {
            SaySomething();
            return 0;
        }

    (1)【虚函数】NullPtr->Virtual_Method()

        void SaySomething(void)
        {
            AA * pAA = NULL;
            pAA->SayHello(0); // 虚函数.
        }

      DUMP 文件:

      FAULTING_IP: 
        ds!SaySomething+2c [f:my project1111dsds.cpp @ 121]
        0019d91c 8b10            mov     edx,dword ptr [eax]
        EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
            ExceptionAddress: 0019d91c (ds!SaySomething+0x0000002c)
            ExceptionCode: c0000005 (Access violation)
            ExceptionFlags: 00000000
        NumberParameters: 2
            Parameter[0]: 00000000
            Parameter[1]: 00000000
            Attempt to read from address 00000000
        FOLLOWUP_IP: 
        ds!SaySomething+2c [f:my project1111dsds.cpp @ 121]
        0019d91c 8b10            mov     edx,dword ptr [eax]
        STACK_TEXT:  
        0033fa60 0019d983 00000000 00000000 7ffdb000 ds!SaySomething+0x2c [f:my project1111dsds.cpp @ 121]
        0033fb34 0019f887 00000001 00411be8 00411c50 ds!main+0x23 [f:my project1111dsds.cpp @ 128]
        0033fb80 0019f75f 0033fb94 76951114 7ffdb000 ds!__tmainCRTStartup+0x117 [f:ddvctoolscrt_bldself_x86crtsrccrt0.c @ 266]
        0033fb88 76951114 7ffdb000 0033fbd4 773bb299 ds!mainCRTStartup+0xf [f:ddvctoolscrt_bldself_x86crtsrccrt0.c @ 182]
        0033fb94 773bb299 7ffdb000 421f5b46 00000000 kernel32!BaseThreadInitThunk+0xe
        >> 在调用 NullPtr->Virtual_Method() 的函数内产生异常. <<

      原因:

       pAA->SayHello(0);
        008DD915  mov         esi,esp 
        008DD917  push        0    
        008DD919  mov         eax,dword ptr [pAA] 
        008DD91C  mov         edx,dword ptr [eax] <------- AV : 因为 指针为0, 0地址的虚函数表指针也是0. 当访问虚函数表的时候, 就会出现异常。
        008DD91E  mov         ecx,dword ptr [pAA] 
        008DD921  mov         eax,dword ptr [edx]
        008DD923  call        eax  

     2) 【成员函数】NullPtr->Member_Method() 

       void SaySomething(void)
        {
            AA * pAA = NULL;
            pAA->SayHello(); // 成员函数.
        }

      DUMP 文件:

      FAULTING_IP: 
        ds!AA::SayHello+26 [f:my project1111dsds.cpp @ 109]
        01256996 c7400400000000  mov     dword ptr [eax+4],0
        EXCEPTION_RECORD:  ffffffff -- (.exr 0xffffffffffffffff)
        ExceptionAddress: 01256996 (ds!AA::SayHello+0x00000026)
            ExceptionCode: c0000005 (Access violation)
            ExceptionFlags: 00000000
        NumberParameters: 2
            Parameter[0]: 00000001
            Parameter[1]: 00000004
        Attempt to write to address 00000004
        FOLLOWUP_IP: 
        ds!AA::SayHello+26 [f:my project1111dsds.cpp @ 109]
        01256996 c7400400000000  mov     dword ptr [eax+4],0
        STACK_TEXT:  
        0016f964 0125693d 0016fb18 00000000 7ffdc000 ds!AA::SayHello+0x26 [f:my project1111dsds.cpp @ 109]
        0016fa44 01256a73 00000000 00000000 7ffdc000 ds!SaySomething+0x2d [f:my project1111dsds.cpp @ 122]
        0016fb18 01263567 00000001 004c1be8 004c1c50 ds!main+0x23 [f:my project1111dsds.cpp @ 128]
        0016fb64 0126343f 0016fb78 76951114 7ffdc000 ds!__tmainCRTStartup+0x117 [f:ddvctoolscrt_bldself_x86crtsrccrt0.c @ 266]
        0016fb6c 76951114 7ffdc000 0016fbb8 773bb299 ds!mainCRTStartup+0xf [f:ddvctoolscrt_bldself_x86crtsrccrt0.c @ 182]
        0016fb78 773bb299 7ffdc000 4239a0bf 00000000 kernel32!BaseThreadInitThunk+0xe
        >> 在 被调用的 NullPtr->SayHello() 函数内产生异常 <<
        

      原因:

      pAA->SayHello();

      因为是调用成员函数, 所以是 "静态绑定" 但是在 SayHello() 的内部:

       m_nValue = 0;
        013F6993  mov         eax,dword ptr [this] 
        013F6996  mov         dword ptr [eax+4],0    <--- 异常 : 因为 this 指针来源于 pAA (ECX), 因为 this 指针指向 0, 所以成员变量的地址是非法值 (0~64K), 所以AV.
     PS : 如果成员函数不需要访问成员变量, 那么 NULL->Member_Method() 不会有问题.

      同理:

      class Mgr
        {
            ......
            ......
            AA m_myAAObj;
        }
        
        g_pMgr->m_myAAObj.SayHello();

      SayHello() 要访问成员变量, 那么要知道 this 指针 (即该对象在内存中的位置).

     ECX = g_pMgr     + offsetof (m_myAAObj);
         = g_pMgr 的值 + m_myAAObj 在 Mgr 中的偏移.

      如果 g_pMgr 指向了 NULL, 那么 ECX 的值只是偏移; 反之, 当发现 ECX 的值是个很小的值, 如果该值是偏移, 说明 g_pMgr 值 NULL。

    结论:

      NULL->虚函数()   是访问虚函数表时引起AV.
      NULL->成员函数() 是该成员函数访问成员变量引起的AV.

  • 相关阅读:
    诡异的命名空间问题
    如何为自定义属性提供表达式绑定支持
    为SSIS编写自定义数据流组件(DataFlow Component)之进阶篇:自定义编辑器
    SSAS : 外围应用配置器
    SSAS : 数据访问接口整理汇总
    SSAS : ADOMDConnection.ConnectionString的参数列表
    SSIS中的字符映射表转换组件
    SSAS: Discover 何处寻? 一切尽在GetSchemaDataSet
    为SSIS编写简单的同步转换组件
    如何在同步转换组件中增加输出列
  • 原文地址:https://www.cnblogs.com/happylong/p/4501573.html
Copyright © 2020-2023  润新知