为什么 C# 访问 null 字段会抛异常?

一:背景

1. 一个有趣的话题

最近在看 硬件异常 相关知识,发现一个有意思的空引用异常问题,拿出来和大家分享一下,为了方便讲述,先上一段有问题的代码。

namespace ConsoleApp2
{internal class Program{static Person person = null;static void Main(string[] args){var age = person.age;Console.WriteLine(age);}}public class Person{public int age;}
}

由于 person 是一个 null 对象,很显然这段代码会抛异常,那为什么会抛异常呢?要想找原因,需要从最底层的汇编研究起。

二:异常原理分析

1. 从汇编上寻找答案

可以使用 Visual Studio 2022 的反汇编窗口,观察 var age = person.age; 处到底生成了什么。

----------------  var age = person.age;   ----------------081D6154  mov         ecx,dword ptr ds:[4C41F4Ch]  
081D615A  mov         ecx,dword ptr [ecx+4]  
081D615D  mov         dword ptr [ebp-3Ch],ecx

这三句汇编还是很好理解的,4C41F4Ch 存放的是 person 对象, ecx+4 是取 person.age,最后一句就是将 age 放在 ebp-3Ch 栈位置上,接下来我们来看下 null 时的 ecx 到底是多少,截图如下:

424e073701e0b4b40b5279b0a68a7073.png

从图中可以看到,此时的 ecx=0000000,如果大家了解 windows 的虚拟内存布局,应该知道在虚拟内存的 0~0x0000ffff 范围内是属于 null 禁入区,凡是落在这个区一概属访问违例,画个图就像下面这样。

36c0b83dc6f06b5dbd687ab38764c53f.png

到这里原理就搞清楚了,因为 [ecx+4] = [4] 是落在这个 null 区所致, 但是。。。。 大家有没有发现一个问题,对,就是这里的 [ecx+4],因为这里有一个 +4 偏移来取 age 字段,那我能不能在 person 中多定义一些字段,然后取最后一个字段从而从 null 区 冲出去。。。哈哈。

2. 真的可以冲出 null 区吗

有了这个想法之后,我决定在 Person 类中定义 10w 个 age 字段,参考代码如下:

namespace ConsoleApp2
{internal class Program{static Person person = null;static void Main(string[] args){var str = @"public class Person{{0}}";var lines = Enumerable.Range(0, 100000).Select(m => $"public int age{m};");var fields = string.Join("\n", lines);var txt = str.Replace("{0}", fields);File.WriteAllText("Person.cs", txt);Console.WriteLine("person.cs 生成完毕");}}
}

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

internal class Program{static Person person = null;static void Main(string[] args){var age = person.age99999;Console.WriteLine(age);}}
db7d6478afd34426d346b241b0543387.png

我去,万万没想到,把 ClassLoader 给弄崩了。。。。得,那只能改 20000 个 age 试试看吧,参考代码如下:

internal class Program{static Person person = null;static void Main(string[] args){var age = person.age19999;Console.WriteLine(age);}}

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

------------- var age = person.age19999;  -------------
0804657E  mov         ecx,dword ptr ds:[49F1F4Ch]  
08046584  mov         dword ptr [ebp-40h],ecx  
08046587  mov         ecx,dword ptr [ebp-40h]  
0804658A  cmp         dword ptr [ecx],ecx  
0804658C  mov         ecx,dword ptr [ebp-40h]  
0804658F  mov         ecx,dword ptr [ecx+13880h]  
08046595  mov         dword ptr [ebp-3Ch],ecx

从上面的汇编代码可以看出几点信息。

  • 汇编代码行数多了。

  • ecx+13880h 冲出了 null 区(FFFF) 的边界。

接下来单步调试汇编,发现在 cmp dword ptr [ecx],ecx 处抛了异常。。。

37cf25a02e2361bc13ef788ba218e994.png

大家都知道此时的 ecx 的地址是 0 ,从 ecx 上取内容肯定会抛访问违例,而且这段代码很诡异,一般来说 cmp 之后都是类似 jz,jnz 跳转指令,而它仅仅是个半残之句。。。

从这些特征看,这是 JIT 故意在取偏移之前尝试判断 ecx 是不是 null,动机不纯哈。。。。

三:总结

从这些分析中可以得知,JIT 还是很智能的。

  • 当偏移值落在 0~FFFF 禁入区内,JIT 就不生成判断代码来减少代码体积。

  • 在偏移值冲出了 0~FFFF 禁入区,JIT 不得不生成代码来判断。

哈哈,本篇是不是很有意思,希望对大家有帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285593.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言试题一百之输入某年某月某日,判断这一天是这一年的第几天

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入某年某月某日,判断这一天是这一年的第几天? 分析: 以 3 月 5 日为例,应该先把…

[转]Java学习路线图(完整详细2019版)

一门永不过时的编程语言——Java 软件开发。 Java编程语言占比: 据官方数据统计,在全球编程语言工程师的数量上,Java编程语言以1000万的程序员数量位居首位。 而且很多软件的开发都离不开Java编程,因此其程序员的数量最多。而在…

【CASS精品教程】Win7+CAD2008+CASS9.1(含CASS3D)完美安装教程(附完整软件安装包下载)

本文讲解win764位系统上安装CAD2008+CASS9.1(含CASS3D)免费版安装,文末附完整软件下载地址,亲测可用!!! 文章目录 1. CAD2008安装2. CASS9.1安装3. 软件下载地址1. CAD2008安装 双击安装包中的Setup.exe,开始安装。 点击【安装产品】。

(十一)Jmeter另一种调试工具 HTTP Mirror Server

之前我介绍过Jmeter的一种调试工具Debug Sampler,它可以输出Jmeter的变量、属性甚至是系统属性而不用发送真实的请求到服务器。既然这样,那么HTTP Mirror Server又是做什么用的呢? 一、HTTP Mirror Server的作用: 它可以在本地临…

C语言九十八之实现企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万元,低于 20 万元时,低于 10 万元的部分按 10%提成,高于 10 万元的

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 企业发放的奖金根据利润提成。利润(I)低于或等于 10 万元时,奖金可提 10%;利润高 于 10 万…

[转]大数据环境搭建步骤详解(Hadoop,Hive,Zookeeper,Kafka,Flume,Hbase,Spark等安装与配置)

大数据环境安装和配置(Hadoop2.7.7,Hive2.3.4,Zookeeper3.4.10,Kafka2.1.0,Flume1.8.0,Hbase2.1.1,Spark2.4.0等) 系统说明搭建步骤详述 一、节点基础配置 二、Hadoop安装和配置三、…

C# Any()和AII()方法

我们常常需要的另一类查询是确定数据是否满足某个条件,或者确保所有数据都满足某个条件。例如,需要确定某个产品是否已经脱销(库存为 0),或者是否发生了某个交易。LINQ 提供了两个布尔方法:Any()和 All(),它们可以快速…

初级图像混合——线性混合操作

addWeighted函数 这个函数的作用是,计算两个数组(图像阵列)的加权和。原型如下: void addWeighted(InputArray src1, double alpha, InputArray src2, double beta, double gamma, OutputArray dst, int dtype-1); 第一个参数&am…

C语言九十九之实现一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多少?

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 一、题目 一个整数,它加上 100 后是一个完全平方数,再加上 168 又是一个完全平方数,请问该数是多…

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一)

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(四) 【专升本计算机】2021…

快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码

这是 ASP.NET Core Identity 系列的第四篇文章,上一篇文章讲解了如何在 ASP.NET Core Identity 中实现用户登录与登出。这篇文章讲一讲如何在 ASP.NET Core Identity 中通过邮件服务实现用户账号的密码重置。点击上方或后方蓝字,阅读 ASP.NET Core Ident…

[.net 面向对象程序设计深入](4)MVC 6 —— 谈谈MVC的版本变迁及新版本6.0发展方向...

[.net 面向对象程序设计深入](4)MVC 6 ——谈谈MVC的版本变迁及新版本6.0发展方向 1.关于MVC 在本篇中不再详细介绍MVC的基础概念,这些东西百度要比我写的全面多了,MVC从1.0到5.0的时间也不短了,很多人只是按照范例去使…

C语言试题101之输入三个整数 x,y,z,请把这三个数由小到大输出

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:输入三个整数 x,y,z,请把这三个数由小到大输出 分析:想办法把最小的数放到 x 上,先…

[转]史上最全的后端技术大全,你都了解哪些技术呢?

导语:工欲善其事,必先利其器;士欲宣其义,必先读其书。后台开发作为互联网技术领域的掌上明珠,一直都是开发者们的追逐的高峰。本文将从后台开发所涉及到的技术术语出发,基于系统开发、架构设计、网络通信等…

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二)

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(四) 【专升本计算机】2021…

WPF 开源控件库Extended WPF Toolkit介绍(经典)

01—Extended WPF Toolkit介绍Extended WPF Toolkit 可以说是WPF Toolkit 的一个补充,Extended WPF Toolkit包含了标准的WPF Toolkit里没有的Windows Presentation Foundation(WPF)控件、工具和组件。Extended WPF Toolkit是创建下一代Window…

C语言试题102之用*号输出字母 C 的图案

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:用号输出字母 C 的图案 分析:可先用’号在纸上写出字母 C,再分行输出。 2 、温馨提…

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三)

【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(一) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(二) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(三) 【专升本计算机】2021年甘肃省专升本计算机全真模拟试题(四) 【专升本计算机】2021…

WPF 用代码实现WrapPanel右侧自动对齐(解决多余空白问题)

未处理前效果&#xff1a; 处理后效果&#xff1a; <Border Background"{StaticResource BorderBg}" BorderThickness"2" BorderBrush"{StaticResource BorderBrush}" CornerRadius"5" Padding"5" x:Name"SvK…

.NET 中的引用程序集

.NET 中的引用程序集Intro在 .NET 里有一种特殊的程序集叫做 ReferenceAssembly(引用程序集)&#xff0c;引用程序集&#xff08;Reference Assemblies&#xff09; 是一种特殊类型的程序集&#xff0c;它只包含表示库的公共 API 所需的最少元数据量。它们包括在生成工具中引用…