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的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。