空指针带来的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 project\1111\ds\ds.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 project\1111\ds\ds.cpp @ 121]
    0019d91c 8b10            mov     edx,dword ptr [eax]
    STACK_TEXT:
    0033fa60 0019d983 00000000 00000000 7ffdb000 ds!SaySomething+0x2c [f:\my project\1111\ds\ds.cpp @ 121]
    0033fb34 0019f887 00000001 00411be8 00411c50 ds!main+0x23 [f:\my project\1111\ds\ds.cpp @ 128]
    0033fb80 0019f75f 0033fb94 76951114 7ffdb000 ds!__tmainCRTStartup+0x117 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 266]
    0033fb88 76951114 7ffdb000 0033fbd4 773bb299 ds!mainCRTStartup+0xf [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.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 project\1111\ds\ds.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 project\1111\ds\ds.cpp @ 109]
    01256996 c7400400000000  mov     dword ptr [eax+4],0
    STACK_TEXT:
    0016f964 0125693d 0016fb18 00000000 7ffdc000 ds!AA::SayHello+0x26 [f:\my project\1111\ds\ds.cpp @ 109]
    0016fa44 01256a73 00000000 00000000 7ffdc000 ds!SaySomething+0x2d [f:\my project\1111\ds\ds.cpp @ 122]
    0016fb18 01263567 00000001 004c1be8 004c1c50 ds!main+0x23 [f:\my project\1111\ds\ds.cpp @ 128]
    0016fb64 0126343f 0016fb78 76951114 7ffdc000 ds!__tmainCRTStartup+0x117 [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.c @ 266]
    0016fb6c 76951114 7ffdc000 0016fbb8 773bb299 ds!mainCRTStartup+0xf [f:\dd\vctools\crt_bld\self_x86\crt\src\crt0.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.

时间: 2024-10-30 22:13:31

空指针带来的AV异常.的相关文章

python升级带来的yum异常:File &quot;/usr/bin/yum&quot;, line 30

问题: $ yum File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: ^ SyntaxError: invalid syntax 原因: 这是因为yum采用Python作为命令解释器,这可以从/usr/bin/yum文件中第一行#!/usr/bin/python发现.而python版本之间兼容性不太好,使得2.X版本与3.0版本之间存在语法不一致问题.而CentOS 5自带的yum采用的是python2.4,当系统将py

Oracle 11g、12c大量错误登陆尝试带来的数据库异常

APPLIES TO: Oracle Database - Enterprise Edition - Version 10.2.0.5 and later Information in this document applies to any platform. CAUSE A hang is possible in earlier versions of RDBMS as a result of an unpublished bug fixed in the following version

python升级带来的yum异常(解决错误File &quot;/usr/bin/yum&quot;, line 30 except KeyboardInterrupt, e:)

解决错误File "/usr/bin/yum", line 30 except KeyboardInterrupt, e: 错误: 原因: 这是因为yum采用python作为命令解释器,原来系统自带的python解释器为python2.7,然后我之前为了方便将python默认的解释器设为了python3.6,导致按python3.6解析2.7的语法出错了. 解决方法: 修改/usr/bin/yum文件中的第一行为#!/usr/bin/python2.7 可能你的系统不是2.7,通过ta

字体不同,造成的显示异常

今天在做CSS那些事的时候,发现一个有意思的现象: 不同字体设置,会显示出不同的效果或者说异常 先看代码: 1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>跟随标题时间的新闻列表——2</title> 5 <meta charset="utf-8"> 6 <style> 7 .news_list *{ margin:0; padding:0; list-styl

有关错误与异常的总结

错误和异常的区别(Error vs Exception) 1)  error都是继承自父类java.lang.Error,而exception都继承自java.lang.Exception. 2)  再看看JDK中对于java.lang.Error和java.lang.Exception的解释.    java.lang.Error: An Error is a subclass of Throwable that indicates serious problems that a reason

一些Windows API导致的Crash以及使用问题总结(API的AV失败,可以用try catch捕捉后处理)

RegQueryValueEx gethostbyname/getaddrinfo _localtime64 FindFirstFile/FindNextFile VerQueryValue CreateFileMapping相关 SetDllDirectory Windows API就没有问题.没有BUG吗?答案是否定的!代码都是写出来,怎么可能完全没有问题呢?下面我们就来看看目前发现有哪些Windows API是有问题的,或者说使用上面有误区的. 1.RegQueryValueEx 首先看看

java异常——RuntimeException和User Define Exception

1.RuntimeException public class RuntimeException { public static void main(String[] args) { // TODO Auto-generated method stub String str="123"; int temp=Integer.parseInt(str); System.out.println(temp*temp); } } 查看parseInt方法的源代码如下: public static

Java中避免空指针查昂见的方法

什么是空指针? 当一个变量的值为null时,在Java里表示一个不存在的空对象,没有实际内容,没有给它分配内存,null也是对象成员的默认值.所以,一个对象如果没有进行初始化操作,这时如果调用这个对象的方法或者变量,就会出现空指针异常.例如: Object obj = null; String str = obj.toString(); 空指针属于运行时异常RuntimeException的子类,它不是捕获型异常,只有在程序运行时才可能报出来,而且会造成程序中断. 如何避免空指针? 1.字符串比

Java自学-异常处理 异常分类

Java 中异常的分类 异常分类: 可查异常,运行时异常和错误3种 其中,运行时异常和错误又叫非可查异常 步骤 1 : 可查异常 可查异常: CheckedException 可查异常即必须进行处理的异常,要么try catch住,要么往外抛,谁调用,谁处理,比如 FileNotFoundException 如果不处理,编译器,就不让你通过 package exception; import java.io.File; import java.io.FileInputStream; import