9

基本上,内存损坏是由覆盖你不应该覆盖的内存引起的。我想知道这是否可能在 C# 中使用不安全的代码(即不是通过调用外部非托管代码)。我看到两种可能的情况:

  • 访问空指针 -> 被 CLR 捕获,抛出 NullReferenceException
  • 访问指向无效随机内存位置的指针 -> 被 CLR 捕获,抛出 AccessViolationException

在这两种情况下,运行时似乎都会检测并防止发生潜在的内存损坏。因此,是否有可能使用不安全的代码从 C# 中破坏内存?作为推论,从不安全的代码中捕获 AccessViolationExceptions 是否安全?

4

4 回答 4

12

你错过了大子弹:

  • 访问内存并且没有收到 AccessViolationException。

常见,.NET 程序中总是有很多可写内存。包括将元素写入数组末尾之外,它很少会发生炸弹。内存保护在内存页面边界上是细粒度的,在 Windows 上为 4096 字节。.NET GC 大大提高了这一点,分代堆段是 VM 的大块。捕捉 AVE 是非常不明智的。

一些可以玩的代码:

class Program {
    static unsafe void Main(string[] args) {
        var arr = new byte[1];
        for (int fill = 0; fill < 2 * 1024 - 64; ++fill) {
            byte[] dummy = new byte[1024];
        }
        fixed (byte* p = &arr[0]) {
            for (int ix = 1; ; ++ix)
                p[ix] = 42;
        }
    }
}

过冲约 1.5 兆字节。

于 2013-08-21T20:13:01.553 回答
10

访问指向无效随机内存位置的指针

如果是读取,它是安全的。如果是写入,如果内存位置碰巧是有效的,但您并不拥有它,那么它是不安全的。您将在随机内存位置上涂鸦。

作为推论,从不安全的代码中捕获 AccessViolationExceptions 是否安全?

不,因为该异常告诉您 a) 您有错误 b) 内存可能已损坏且无法修复。抓住它并尽快拆除这个过程。

于 2013-08-21T19:46:02.303 回答
7

C# 中的不安全代码会导致内存损坏吗?

答案是肯定的!,考虑下面的例子

int a = 10;
int* p = &a;
*(p+54)= 444;

CLR 可能会或可能不会捕获此问题。

并非所有通过错误指针进行的读取或写入都会导致访问冲突,因此访问冲突通常表示通过错误指针发生了多次读取或写入,并且内存可能已损坏。

来自Accessviolationexception 文档

于 2013-08-21T19:55:34.480 回答
2

导致 AccessViolationException 的内存写入没有发生,它没有做任何事情。

但是:它试图写入错误位置的事实是一个非常强烈的指标,表明之前可能存在无效的写入操作(因为您的代码有错误),并且这些写入可能指向可写但不是的位置应该改变。

于 2013-08-21T19:50:44.410 回答