中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#訪問null字段會拋異常的原因是什么

發布時間:2022-06-30 14:12:26 來源:億速云 閱讀:118 作者:iii 欄目:開發技術

這篇文章主要介紹“C#訪問null字段會拋異常的原因是什么”,在日常操作中,相信很多人在C#訪問null字段會拋異常的原因是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C#訪問null字段會拋異常的原因是什么”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

一:舉例說明 

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

C#訪問null字段會拋異常的原因是什么

從圖中可以看到,此時的 ecx=0000000,如果大家了解 windows 的虛擬內存布局,應該知道在虛擬內存的 0~0x0000ffff 范圍內是屬于 null 禁入區,凡是落在這個區一概屬訪問違例,畫個圖就像下面這樣。

C#訪問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);
        }
    }

C#訪問null字段會拋異常的原因是什么

我去,萬萬沒想到,把 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 處拋了異常。。。

C#訪問null字段會拋異常的原因是什么

大家都知道此時的 ecx 的地址是 0 ,從 ecx 上取內容肯定會拋訪問違例,而且這段代碼很詭異,一般來說 cmp 之后都是類似 jz,jnz 跳轉指令,而它僅僅是個半殘之句。。。

從這些特征看,這是 JIT 故意在取偏移之前嘗試判斷 ecx 是不是 null,動機不純哈。

到此,關于“C#訪問null字段會拋異常的原因是什么”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宣汉县| 天津市| 玛沁县| 百色市| 昂仁县| 陆河县| 苏尼特左旗| 南开区| 乐业县| 乌鲁木齐县| 阜阳市| 镇雄县| 博野县| 卫辉市| 广安市| 和顺县| 莱芜市| 平乐县| 会宁县| 休宁县| 安吉县| 舟山市| 大悟县| 通城县| 湖南省| 郓城县| 泉州市| 冀州市| 永登县| 罗定市| 五寨县| 姚安县| 武夷山市| 饶阳县| 沐川县| 沂水县| 育儿| 永丰县| 渝北区| 故城县| 依兰县|