当前位置:网站首页>Why does C throw exceptions when accessing null fields?

Why does C throw exceptions when accessing null fields?

2022-06-27 03:47:00 Dotnet cross platform

One : background

1. An interesting topic

Recently in to see Hardware exception Related knowledge , Found an interesting null reference exception problem , Take it out and share it with you , For the convenience of narration , Let's start with a problematic code .

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;
    }
}

because person It's a null object , Obviously this code throws exceptions , So why throw exceptions ? To find out why , You need to start with the lowest level of assembly .

Two : Abnormal principle analysis

1. Look for the answer from the compilation

have access to Visual Studio 2022 Disassembly window for , Observe var age = person.age; What exactly is generated at .

----------------  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

These three sentences are easy to understand ,4C41F4Ch Deposit is person object , ecx+4 Is to take person.age, The last sentence is to age Put it in ebp-3Ch Stack position , Let's take a look at null At the time of the ecx How much is it , The screenshot is as follows :

424e073701e0b4b40b5279b0a68a7073.png

As you can see from the diagram , At this time ecx=0000000, If you know windows Virtual memory layout , You should know that in the virtual memory 0~0x0000ffff The scope belongs to null Exclusion zone , Anyone who falls in this area is a visit violation , Draw a picture like this .

36c0b83dc6f06b5dbd687ab38764c53f.png

The principle will be clear here , because [ecx+4] = [4] It fell on this null Area caused , however .... Have you found a problem , Yes , It's here [ecx+4], Because there's a +4 Offset to get age Field , Can I just person Define more fields in , Then take the last field from null District Rush out ... ha-ha .

2. Can really rush out null District

With this idea , I've decided to Person Definition in class 10w individual age Field , The reference codes are as follows :

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  Generation completed ");
        }
    }
}

After code execution ,Person.cs Will be generated as scheduled , Next read person.age99999 See if miracles happen , The reference codes are as follows :

internal class Program
    {
        static Person person = null;

        static void Main(string[] args)
        {
            var age = person.age99999;

            Console.WriteLine(age);
        }
    }
db7d6478afd34426d346b241b0543387.png

I went to , Never in my wildest dreams , hold ClassLoader It broke up .... have to , That can only be changed 20000 individual age Have a try. , The reference codes are as follows :

internal class Program
    {
        static Person person = null;

        static void Main(string[] args)
        {
            var age = person.age19999;

            Console.WriteLine(age);
        }
    }

Next, we put the breakpoint in var age = person.age19999; Continue to look at disassembly code .

------------- 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

From the assembly code above, we can see some information .

  • There are too many lines of assembly code .

  • ecx+13880h Out null District (FFFF) The boundary of the .

Next, step through the assembly , Found in cmp dword ptr [ecx],ecx An exception was thrown at ...

37cf25a02e2361bc13ef788ba218e994.png

We all know that at this time ecx The address is 0 , from ecx Fetching content will definitely throw access violations , And this code is weird , Generally speaking cmp After that, it is similar jz,jnz Jump instruction , And it is only a half broken sentence ...

From these characteristics , This is a JIT Deliberately try to judge before taking the offset ecx Is it right? null, The motive is not pure ....

3、 ... and : summary

From these analyses we can see that ,JIT Still very intelligent .

  • When the offset value falls at 0~FFFF No entry zone ,JIT No judgment code is generated to reduce the code volume .

  • At the offset value, the 0~FFFF Exclusion zone ,JIT Have to generate code to judge .

ha-ha , Is this article very interesting , Hopefully that helped .

原网站

版权声明
本文为[Dotnet cross platform]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/178/202206270336358145.html