为什么这个不安全的代码会抛出NullReferenceException ?

本文关键字:NullReferenceException 代码 不安全 为什么 | 更新日期: 2023-09-27 18:19:04

我在code Golf的一个问题上使用不安全的代码,我发现了一些我无法解释的东西。这段代码:

unsafe
{
    int i = *(int*)0;
}

由于访问冲突(段错误)而崩溃,但是以下代码:

unsafe
{
    *(int*)0=0;
}

抛出NullReferenceException。在我看来,第一个正在执行读操作,第二个正在执行写操作。一个异常告诉我,CLR中的某个地方正在拦截写操作,并在操作系统杀死进程之前停止它。为什么这种情况发生在写操作中,而不是在读操作中?如果我使指针值足够大,它会在写操作中出现段错误。这是否意味着CLR知道有一块内存是保留的,甚至不会尝试写入?为什么它允许我从那个块中读取数据呢?我是不是完全误解了什么?

编辑:

有趣的是:System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0);给了我一个访问冲突,而不是NullReference。

为什么这个不安全的代码会抛出NullReferenceException ?

第一个异常当然是有意义的——您试图从内存地址0读取。第二个更有趣一些。在c++中,有一个名为NULL的宏/常量,其值为0。它用于无效的指针地址——很像c#中引用类型的null值。由于c#引用是内部指针,当你试图从该地址(NULL或0)读/写时,会发生NullReferenceException;事实上,从0到64K的地址在所有进程中都是无效的(在Windows中),以便捕捉程序员的错误。确切的异常或错误可能因计算机硬件或Windows/版本而略有不同。. NET框架,但你应该得到一个错误的代码片段。

至于读/写随机地址时的段错误,这是由于操作系统对每个进程的隔离。你不能乱动其他进程的代码或数据——至少不能合法地乱动。