c# - 现代 .Net 中未对齐的指针有多安全?

标签 c# memory memory-alignment

我需要从 native 内存读取/写入一堆结构。我想弄清楚我是否应该为结构对齐而烦恼。 这是我编写的用于测试的简单代码。它将压缩结构写入未对齐的指针,然后读回该结构:

public static unsafe class Program
{
    public static void Main()
    {
        Console.WriteLine(sizeof(MyStructPacked)); //returns 6, as expected (no padding) 

        var nativeMemory = Marshal.AllocHGlobal(33);

        var ptr = (byte*)nativeMemory.ToPointer();
        Console.WriteLine((int)ptr % 8 == 0); //true, pointer is aligned to 8 bytes
        Console.WriteLine((int)ptr % 16 == 0); //true, pointer is also aligned to 16 bytes
        
        Unsafe.InitBlock(ptr, 0, 33);
        //!!! aligned write to unaligned pointer
        Unsafe.Write(ptr + 3, new MyStructPacked{Short = ushort.MaxValue / 2, Int = UInt32.MaxValue});
        for (int i = 0; i < 10; i++)
        {
            byte b = *(ptr + i);
            //returns 0 0 0 255 127 255 255 255 255 0 (which is correct)
            Console.WriteLine(b);
        }
        
        //!!! aligned read from unaligned pointer
        var read1 = Unsafe.Read<MyStructPacked>(ptr + 3);
        //unaligned read from unaligned pointer
        var read2 = Unsafe.ReadUnaligned<MyStructPacked>(ptr + 3);
        //!!! dereferencing unaligned pointer
        var read3 = *(MyStructPacked*)(ptr + 3);
        
        //all produce the same (correct) result.
        Console.WriteLine(read1.Int + " " + read1.Short);
        Console.WriteLine(read2.Int + " " + read2.Short);
        Console.WriteLine(read3.Int + " " + read3.Short);

        //!!! aligned read from unaligned pointer
        var readInt1 = Unsafe.Read<uint>(ptr + 5);
        //unaligned read from unaligned pointer
        var readInt2 = Unsafe.ReadUnaligned<uint>(ptr + 5);
        //!!! dereferencing unaligned pointer
        var readInt3 = *(uint*)(ptr + 5);
        
        //all return uint.MaxValue (also correct)
        Console.WriteLine(readInt1);
        Console.WriteLine(readInt2);
        Console.WriteLine(readInt3);

        Marshal.FreeHGlobal(nativeMemory);
    }
}

[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyStructPacked
{
    public ushort Short;
    public uint Int;
}

我在手头的几个系统(使用 .Net 6.0)上测试了它,它在它们上运行没有问题。规范说值类型必须以某种方式对齐,但我找不到任何关于如果指针未按照规范对齐的方式实际发生什么的信息。我能找到的最好的是它被认为是“未定义的行为”(提到 here ),这不是很有帮助。

所以我的问题是,上面的代码有多安全?我可以期望它在其他 .Net 支持的系统和平台上运行吗?或者它的工作纯粹是偶然的?如果它在某些系统上不起作用,那么最坏的情况是什么?这段代码会崩溃吗?有什么我可以做的来重现潜在的问题(也许在特定系统上运行它?)?欢迎在这里提出任何建议,谢谢。

附言我知道未对齐访问对性能的影响,但这些都是次要问题。目前主要关注的是执行安全。

最佳答案

我在 armv7 处理器上遇到了问题,这些问题在低端领域相对常见。如果您尝试取消引用未对齐的指针(使用安全的 ref 运算符或不安全的 *),它们实际上会抛出实际的异常。该问题很容易重现,并且异常消息非常明确。

所以最后我不得不手动对齐所有必须通过引用访问的非托管内存。这很乏味,但很好......易于管理。如果您不需要通过引用访问内存,Unsafe.ReadUnalignedUnsafe.WriteUnaligned 方法也可以防止异常(显然以访问速度为代价)。

关于c# - 现代 .Net 中未对齐的指针有多安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72923219/

相关文章:

c# - Dapper 多映射多对多关系

c# - 组合框 SelectedItem 未按预期工作

iphone - 通过分割 .xib 文件来减少内存使用?

Haskell,限制 GHCI 内存

assembly - 对齐节的开头是什么意思?

c# - 为什么我在这个简单的 Monotouch 代码中看到 "Object of class __NSCFString autoreleased with no pool in place"?

c# - 使用 MySql MySQLMembershipProvider - autogenerateschema ="true"不工作?

c - 构建一个带有一些内核内存泄露的应用程序

c++ - 标准全局默认运算符 new 的对齐限制是什么?

c - 访问结构 union 中结构的第一个字段