备受期待的上海大歌剧院主体已完工,目前正进入内部装修冲刺阶段。日前,上海歌剧院院长石倚洁带队赴现场参观调研,面对恢弘大气的主歌剧舞台,一时忍不住登台即...
2026-04-14 5
一:背景1. 一个有趣的话题
最近在看 硬件异常 相关知识,发现一个有意思的空引用异常问题,拿出来和大家分享一下,为了方便讲述,先上一段有问题的代码。
namespaceConsoleApp2
internalclassProgram
staticPerson person = null;
staticvoidMain( string[] args )
varage = person.age;
Console.WriteLine(age);
publicclassPerson
publicintage;
由于 person 是一个 null 对象,很显然这段代码会抛异常,那为什么会抛异常呢?要想找原因,需要从最底层的汇编研究起。
二:异常原理分析1. 从汇编上寻找答案
可以使用 Visual Studio 2022 的反汇编窗口,观察 var age = person.age; 处到底生成了什么。
---------------- varage = 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 字段,参考代码如下:
namespaceConsoleApp2
internalclassProgram
staticPerson person = null;
staticvoidMain( string[] args )
varstr = @"public class Person
{0}
varlines = Enumerable.Range( 0, 100000).Select(m => $"public int age {m};" );
varfields = string.Join( "\n", lines);
vartxt = str.Replace( "{0}", fields);
File.WriteAllText( "Person.cs", txt);
Console.WriteLine( "person.cs 生成完毕");
代码执行后, Person.cs 就会如期生成,接下来读取 person.age99999 看看有没有奇迹发生,参考代码如下:
internalclassProgram
staticPerson person = null;
staticvoidMain( string[] args )
varage = person.age99999;
Console.WriteLine(age);
我去,万万没想到,把 ClassLoader 给弄崩了。。。。得,那只能改 20000 个 age 试试看吧,参考代码如下:
internalclassProgram
staticPerson person = null;
staticvoidMain( string[] args )
varage = person.age19999;
Console.WriteLine(age);
接下来我们将断点放在 var age = person.age19999; 上继续看反汇编代码。
------------- varage = person.age19999; -------------
0804657E mov ecx,dword ptr ds:[ 49F1F4Ch]
08046584mov dword ptr [ebp -40h],ecx
08046587mov ecx,dword ptr [ebp -40h]
0804658A cmp dword ptr [ecx],ecx
0804658C mov ecx,dword ptr [ebp -40h]
0804658Fmov ecx,dword ptr [ecx+ 13880h]
08046595mov dword ptr [ebp -3Ch],ecx
从上面的汇编代码可以看出几点信息。
汇编代码行数多了。
ecx+13880h 冲出了 null 区(FFFF) 的边界。
汇编代码行数多了。
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 不得不生成代码来判断。
当偏移值落在 0~FFFF 禁入区内,JIT 就不生成判断代码来减少代码体积。
在偏移值冲出了 0~FFFF 禁入区,JIT 不得不生成代码来判断。
哈哈,本篇是不是很有意思,希望对大家有帮助。
相关文章
备受期待的上海大歌剧院主体已完工,目前正进入内部装修冲刺阶段。日前,上海歌剧院院长石倚洁带队赴现场参观调研,面对恢弘大气的主歌剧舞台,一时忍不住登台即...
2026-04-14 5
作者|快刀财经 朱末 靴子落地的瞬间,也宣告了一代快运巨头的“隐退”。 就在3月的最后一天,德邦股份宣布正式终止上市及摘牌,成为2026年A股首家主动...
2026-04-08 7
《蓝皮书》还透露出西安对于相关产业发展的“野心” 海报新闻首席记者 陈嘉伟 报道 4月2日,西安市政府新闻办举行《西安市储能电站、综合能源服务站和大...
2026-04-08 6
3月31日,有博主曝光一段疑似演员宋宁峰出轨“Q女士”的录音,多个相关词条登上热搜榜。 4月1日,宋宁峰发长文承认出轨。他表示,录音中的人确实是自己:...
2026-04-01 7
日本的外交政策正在面临前所未有的考验。两位“邻居”——俄罗斯和中国,似乎达成了一种默契,齐齐对日本发起了攻势,令本就岌岌可危的日本在短时间内倍感压力。...
2026-04-01 5
自从美国和以色列联合对伊朗展开军事行动并成功击毙前最高领袖阿里・哈梅内伊以来,伊朗政权的稳定性面临严峻考验。在这样的背景下,新的最高领袖穆杰塔巴・哈梅...
2026-04-01 5
【文/观察者网 陈思佳】过去几个月,在美国的调解下,俄罗斯和乌克兰已举行多轮谈判,但始终没有取得进展。据俄罗斯塔斯社3月29日报道,俄罗斯总统助理乌沙...
2026-03-30 7
齐鲁晚报·齐鲁壹点 高雅洁 3月27日,青岛市举行“清风寄思 沧海为念”2026年海上追思暨殡仪馆开放日活动,100名海葬逝者家属出海参与海上追思。据...
2026-03-27 5
发表评论