为什么 *(int*)0=0 不会导致访问冲突? [英] Why doesn't *(int*)0=0 cause an access violation?

查看:42
本文介绍了为什么 *(int*)0=0 不会导致访问冲突?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

出于教育目的,我正在编写一组在 C# 中导致运行时异常的方法,以了解所有异常是什么以及导致它们的原因.现在,我正在修补导致 AccessViolationException 的程序.

For educational purposes, I'm writing a set of methods that cause runtime exceptions in C# to understand what all the exceptions are and what causes them. Right now, I'm tinkering with programs that cause an AccessViolationException.

(对我而言)最明显的方法是写入受保护的内存位置,如下所示:

The most obvious way (to me) to do this was to write to a protected memory location, like this:

System.Runtime.InteropServices.Marshal.WriteInt32(IntPtr.Zero, 0);

正如我所希望的,这抛出了一个 AccessViolationException.我想做得更简洁,所以我决定用不安全的代码编写一个程序,并通过将 0 分配给零指针来做(我认为是)完全相同的事情.

Just as I had hoped, this threw an AccessViolationException. I wanted to do it more concisely, so I decided to write a program with unsafe code, and do (what I thought was) exactly the same thing by assigning 0 to the zero-pointer.

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

由于我不知道的原因,这会抛出一个 NullReferenceException.我玩了一些,发现使用 *(int*)1 代替也会抛出 NullReferenceException,但是如果你使用负数,比如 *(int*)-1 它将抛出一个 AccessViolationException.

For reasons that elude me, this throws a NullReferenceException. I played around with it some and found out that using *(int*)1 instead also throws a NullReferenceException, but if you use a negative number, like *(int*)-1 it will throw an AccessViolationException.

这是怎么回事?为什么 *(int*)0 = 0 会导致 NullReferenceException,为什么不会导致 AccessViolationException?

What's going on here? Why does *(int*)0 = 0 cause a NullReferenceException, and why doesn't it cause an AccessViolationException?

推荐答案

取消引用空指针时发生空引用异常;CLR 不关心空指针是一个不安全的指针,其中插入了整数零,还是一个托管指针(即对引用类型对象的引用),其中插入了零.

A null reference exception happens when you dereference a null pointer; the CLR does not care whether the null pointer is an unsafe pointer with the integer zero stuck into it or a managed pointer (that is, a reference to an object of reference type) with zero stuck into it.

CLR 如何知道 null 已被取消引用?CLR 如何知道其他无效指针何时被解除引用?每个指针都指向进程的虚拟内存地址空间中虚拟内存页面中的某处.操作系统会跟踪哪些页面有效,哪些页面无效;当您触摸无效页面时,它会引发 CLR 检测到的异常.然后,CLR 将其显示为无效访问异常或空引用异常.

How does the CLR know that null has been dereferenced? And how does the CLR know when some other invalid pointer has been dereferenced? Every pointer points to somewhere in a page of virtual memory in the virtual memory address space of the process. The operating system keeps track of which pages are valid and which are invalid; when you touch an invalid page it raises an exception which is detected by the CLR. The CLR then surfaces that as either an invalid access exception or a null reference exception.

如果无效访问是对内存底部 64K 的访问,则为 null ref 异常.否则为无效访问异常.

If the invalid access is to the bottom 64K of memory, it's a null ref exception. Otherwise it is an invalid access exception.

这解释了为什么取消引用零和一个会产生空引用异常,以及为什么取消引用 -1 会产生无效访问异常;-1 是 32 位机器上的指针 0xFFFFFFFF,并且该特定页面(在 x86 机器上)始终保留供操作系统用于其自身目的.用户代码无法访问.

This explains why dereferencing zero and one give a null ref exception, and why dereferencing -1 gives an invalid access exception; -1 is pointer 0xFFFFFFFF on 32 bit machines, and that particular page (on x86 machines) is always reserved for the operating system to use for its own purposes. User code cannot access it.

现在,您可能会合理地问,为什么不对指针零执行空引用异常,对其他所有内容执行无效访问异常?因为大多数情况下,当一个小数被取消引用时,这是因为您通过空引用获得了它.想象一下,例如你试图做:

Now, you might reasonably ask why not just do the null reference exception for pointer zero, and invalid access exception for everything else? Because the majority of the time when a small number is dereferenced, it is because you got to it via a null reference. Imagine for example that you tried to do:

int* p = (int*)0;
int x = p[1];

编译器将其翻译成以下等价物:

The compiler translates that into the moral equivalent of:

int* p = (int*)0;
int x = *( (int*)((int)p + 1 * sizeof(int)));

这是解引用 4.但是从用户的角度来看,p[1] 肯定看起来像是对 null 的解引用!所以这就是报告的错误.

which is dereferencing 4. But from the user's perspective, p[1] surely looks like a dereference of null! So that is the error that is reported.

这篇关于为什么 *(int*)0=0 不会导致访问冲突?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆