Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
282 views
in Technique[技术] by (71.8m points)

c# - Why is memory access in the lowest address space (non-null though) reported as NullReferenceException by .NET?

This causes an AccessViolationException to be thrown:

using System;

namespace TestApplication
{
    internal static class Program
    {
        private static unsafe void Main()
        {
            ulong* addr = (ulong*)Int64.MaxValue;
            ulong val = *addr;
        }
    }
}

This causes a NullReferenceException to be thrown:

using System;

namespace TestApplication
{
    internal static class Program
    {
        private static unsafe void Main()
        {
            ulong* addr = (ulong*)0x000000000000FF;
            ulong val = *addr;
        }
    }
}

They're both invalid pointers and both violate memory access rules. Why the NullReferenceException?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is caused by a Windows design decision made many years ago. The bottom 64 kilobytes of the address space is reserved. An access to any address in that range is reported with a null reference exception instead of the underlying access violation. This was a wise choice, a null pointer can produce reads or writes at addresses that are not actually zero. Reading a field of a C++ class object for example, it has an offset from the start of the object. If the object pointer is null then the code will bomb from reading at an address that's larger than 0.

C# doesn't have quite the same problem, the language guarantees that a null reference is caught before you can call an instance method of a class. This is however language specific, it is not a CLR feature. You can write managed code in C++/CLI and generate non-zero null pointer dereferences. Calling a method on a nullptr object works. That method will merrily execute. And call other instance methods. Until it tries to access an instance variable or call a virtual method, which requires dereferencing this, kaboom then.

The C# guarantee is very nice, it makes diagnosing null reference problems much easier since they are generated at the call site and don't bomb somewhere inside a nested method. And it is fundamentally safer, the instance variable might not trigger an exception on extremely large objects when its offset is larger than 64K. Pretty hard to do in managed code btw, unlike C++. But doesn't come for free, explained in this blog post.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...