c++null报错,C++中NULL

  c++null报错,C++中NULL

  一:背景1。一个有趣的话题。最近在看关于硬件异常的知识,发现了一个有趣的空引用异常问题。拿出来和大家分享一下。为了方便讲述,我想从一个有问题的代码开始。

  命名空间控制台2

  {

  内部类程序

  {

  静态Person person=null

  静态void Main(string[] args)

  {

  var age=person.age

  控制台。WriteLine(年龄);

  }

  }

  公共阶层的人

  {

  公共int age

  }

  }既然person是null对象,显然这段代码会抛出异常,那么为什么要抛出异常呢?要找到原因,需要从最底层的组装研究入手。

  2:异常原理分析1。从汇编中寻找答案,可以使用Visual Studio 2022的反汇编窗口观察var age=person.age最后生成的是什么。

  -var age=person . age;-

  081D6154 mov ecx,dword ptr ds:[4C41F4Ch]

  081D615A mov ecx,双字ptr [ecx 4]

  01D615d MOV DWORD PTR [ebp-3Ch],ecx很好理解。4C41F4Ch存储person对象,ecx 4取person.age,最后一句话是把年龄放在EBP-3CH栈上。接下来,让我们来看看ECX为空时是什么。截图如下:

  从图中可以看出,此时ecx=0000000。如果了解windows的虚拟内存布局,应该知道0~0x0000ffff范围内的虚拟内存属于null禁区。任何落在这个区域的人都是违规进入。如下画一个图。

  这里原理很清楚,因为[ecx 4]=[4]是落在这个空区引起的,但是。发现问题了吗?没错,这里是[ecx 4],因为这里有一个4的偏移量来获取年龄字段。那我能不能亲自再定义一些字段,然后让最后一个字段从空区冲出去?哈哈。

  2.真的能冲出空区吗?有了这个想法,我决定在Person类中定义10w年龄字段。参考代码如下:

  命名空间控制台2

  {

  内部类程序

  {

  静态Person person=null

  静态void Main(string[] args)

  {

  var str=@ 公共类人

  {

  {0}

  };

  var lines=可枚举。范围(0,100000)。select(m=$ public int age { m };);

  var字段=字符串。Join(\n ,行);

  var txt=str。替换(“{0}”,字段);

  文件。WriteAllText(Person.cs ,txt);

  控制台。WriteLine(“person . cs generated”);

  }

  }

  }代码执行后,会如期生成Person.cs。接下来读person.age99999看看有没有奇迹。参考代码如下:

  内部类程序

  {

  静态Person person=null

  静态void Main(string[] args)

  {

  var age=person.age99999

  控制台。WriteLine(年龄);

  }

  }

  我去了,没想到,还弄坏了类加载器。是的,只有两万年才能改变。参考代码如下:

  内部类程序

  {

  静态Person person=null

  静态void Main(string[] args)

  {

  var age=person.age19999

  控制台。WriteLine(年龄);

  }

  }接下来我们把断点放在var age=person.age19999继续看反汇编代码。

  -var age=person . age 19999;-

  0804657E mov ecx,dword ptr ds:[49F1F4Ch]

  08046584 mov dword ptr [ebp-40h],ecx

  08046587 mov ecx,dword ptr [ebp-40h]

  0804658A cmp双字指针[ecx],ecx

  0804658C mov ecx,dword ptr [ebp-40h]

  0804658F mov ecx,dword ptr [ecx 13880h]

  0046595 MOV DWORD PTR [EBP-3CH],ECX可以从上面的汇编代码中看到一些信息。

  汇编代码行太多。X13880h冲出了空区(FFFF)的边界。接下来,通过该程序集,我们发现在CMP dword ptr [ecx]和ecx处抛出了一个异常。

  大家都知道此时ecx的地址是0。从ecx取内容肯定会抛出访问违规,这个代码很奇怪。一般来说,在cmp之后,它类似于JZ和JNZ跳转指令,但它只是一个半断句。

  从这些特征来看,这是JIT在取offset之前,刻意去判断ecx是否为null。动机不纯。

  三。总结从这些分析可以知道JIT还是很智能的。

  当偏移值落在0~FFFF的禁区内时,JIT不会生成判断代码,以减少代码量。当偏移值冲出0~FFFF的禁区时,JIT不得不生成代码进行判断。哈哈,这篇文章不是很有意思吗?希望对大家有帮助。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: