返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >探究C#访问null字段会抛异常原因
  • 236
分享到

探究C#访问null字段会抛异常原因

2024-04-02 19:04:59 236人浏览 安东尼
摘要

目录一:举例说明 二:异常原理分析三:总结一:举例说明  namespace ConsoleApp2 { internal class Program

一:举例说明 

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 到底是多少,截图如下:

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

到这里原理就搞清楚了,因为 [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);
        }
    }
 

我去,万万没想到,把 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 处抛了异常。。。

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

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

三:总结

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

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

到此这篇关于探究C#访问null字段会抛异常原因的文章就介绍到这了,更多相关C# null字段异常内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 探究C#访问null字段会抛异常原因

本文链接: https://lsjlt.com/news/153087.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 探究C#访问null字段会抛异常原因
    目录一:举例说明 二:异常原理分析三:总结一:举例说明  namespace ConsoleApp2 { internal class Program ...
    99+
    2024-04-02
  • C#访问null字段会抛异常的原因是什么
    这篇文章主要介绍“C#访问null字段会抛异常的原因是什么”,在日常操作中,相信很多人在C#访问null字段会抛异常的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#访问null字段会抛异常的原因...
    99+
    2023-07-02
  • C++读取访问权限冲突引发异常问题的原因分析
    用C++写代码时经常会遇到“引发了异常: 读取访问权限冲突。”这样的错误提示,这种情况产生原因主要有两点: 一、访问数组越界 当采用线性表的顺序结构,例如顺序表、队列、栈等,用数组存...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作