網(wǎng)站首頁(yè) 編程語(yǔ)言 正文
一:舉例說(shuō)明?
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
?是一個(gè) null 對(duì)象,很顯然這段代碼會(huì)拋異常,那為什么會(huì)拋異常呢?要想找原因,需要從最底層的匯編研究起。
二:異常原理分析
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
?對(duì)象,?ecx+4
?是取 person.age,最后一句就是將 age 放在?ebp-3Ch
?棧位置上,接下來(lái)我們來(lái)看下 null 時(shí)的 ecx 到底是多少,截圖如下:
從圖中可以看到,此時(shí)的?ecx=0000000
,如果大家了解 windows 的虛擬內(nèi)存布局,應(yīng)該知道在虛擬內(nèi)存的?0~0x0000ffff
?范圍內(nèi)是屬于 null 禁入?yún)^(qū),凡是落在這個(gè)區(qū)一概屬訪問(wèn)違例,畫(huà)個(gè)圖就像下面這樣。
到這里原理就搞清楚了,因?yàn)?[ecx+4] = [4] 是落在這個(gè) null 區(qū)所致,?但是。。。。?大家有沒(méi)有發(fā)現(xiàn)一個(gè)問(wèn)題,對(duì),就是這里的?[ecx+4]
,因?yàn)檫@里有一個(gè)?+4
?偏移來(lái)取 age 字段,那我能不能在 person 中多定義一些字段,然后取最后一個(gè)字段從而從?null 區(qū)
?沖出去。。。哈哈。
2. 真的可以沖出 null 區(qū)嗎
有了這個(gè)想法之后,我決定在?Person
?類(lèi)中定義 10w 個(gè) 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 生成完畢"); } } }
代碼執(zhí)行后,Person.cs
?就會(huì)如期生成,接下來(lái)讀取?person.age99999
?看看有沒(méi)有奇跡發(fā)生,參考代碼如下:
internal class Program { static Person person = null; static void Main(string[] args) { var age = person.age99999; Console.WriteLine(age); } }
我去,萬(wàn)萬(wàn)沒(méi)想到,把 ClassLoader 給弄崩了。。。。得,那只能改 20000 個(gè) age 試試看吧,參考代碼如下:
internal class Program { static Person person = null; static void Main(string[] args) { var age = person.age19999; Console.WriteLine(age); } }
接下來(lái)我們將斷點(diǎn)放在?var age = person.age19999;
?上繼續(xù)看反匯編代碼。
------------- 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 ?
從上面的匯編代碼可以看出幾點(diǎn)信息。
- 匯編代碼行數(shù)多了。
- ecx+13880h 沖出了 null 區(qū)(FFFF) 的邊界。
接下來(lái)單步調(diào)試匯編,發(fā)現(xiàn)在?cmp dword ptr [ecx],ecx
?處拋了異常。。。
大家都知道此時(shí)的 ecx 的地址是 0 ,從?ecx
?上取內(nèi)容肯定會(huì)拋訪問(wèn)違例,而且這段代碼很詭異,一般來(lái)說(shuō)?cmp
?之后都是類(lèi)似?jz,jnz
?跳轉(zhuǎn)指令,而它僅僅是個(gè)半殘之句。。。
從這些特征看,這是 JIT 故意在取偏移之前嘗試判斷?ecx
?是不是 null,動(dòng)機(jī)不純哈。。。。
三:總結(jié)
從這些分析中可以得知,JIT 還是很智能的。
- 當(dāng)偏移值落在?
0~FFFF
?禁入?yún)^(qū)內(nèi),JIT 就不生成判斷代碼來(lái)減少代碼體積。 - 在偏移值沖出了?
0~FFFF
?禁入?yún)^(qū),JIT 不得不生成代碼來(lái)判斷。
原文鏈接:https://blog.csdn.net/weixin_67336587/article/details/125534894
相關(guān)推薦
- 2022-09-13 Nginx如何限制IP訪問(wèn)只允許特定域名訪問(wèn)_nginx
- 2022-08-05 RedisConfig 配置文件
- 2022-04-20 Python?設(shè)計(jì)模式中的創(chuàng)建型建造者模式_python
- 2022-11-26 Redis下載部署并加入idea應(yīng)用的小結(jié)_Redis
- 2023-10-10 css像素的問(wèn)題 物理像素 獨(dú)立像素 設(shè)備像素比
- 2022-07-09 python處理excel文件之xlsxwriter?模塊_python
- 2022-09-13 Python?迭代器介紹及作用詳情_(kāi)python
- 2022-10-29 RHCSA 文件編輯 nano vi vim
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過(guò)濾器
- Spring Security概述快速入門(mén)
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支