Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Too wide memory load causes System.AccessViolationException on x64 and ARM64 platforms #78272

Closed
k15tfu opened this issue Nov 12, 2022 · 7 comments
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Milestone

Comments

@k15tfu
Copy link
Contributor

k15tfu commented Nov 12, 2022

Hi!

I faced with System.AccessViolationException when reading 6-byte structure in .NET 7 app on Windows ARM64, Linux x64/ARM64, and macOS x64/ARM64, here is demo app:

using System.IO.MemoryMappedFiles;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace unaligned_access_deref_csharp
{
    internal class Program
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 6)]
        public struct Data
        {
            public UInt32 U32;

            public UInt16 U16;
        }

        static unsafe Data deref(byte* pdata)
        {
            return *(Data*)(pdata);
        }
        
        static unsafe void Main(string[] args)
        {
            var mappedFile = MemoryMappedFile.CreateNew(null, 0x4000);
            var viewAccessor = mappedFile.CreateViewAccessor();
            byte* viewPtr = null;
            viewAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref viewPtr);
            Unsafe.InitBlock(viewPtr, 0x01, (uint)viewAccessor.Capacity);

            _ = deref(viewPtr + viewAccessor.Capacity - Unsafe.SizeOf<Data>());
        }
    }
}

I tried it using .NET SDK 7.0.100 on different platforms, the results are as follows (w/ COMPlus_JitDisasm enabled):

macos-x64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Unix
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       4883EC10             sub      rsp, 16
       488D6C2410           lea      rbp, [rsp+10H]
       48897DF8             mov      qword ptr [rbp-08H], rdi

G_M000_IG02:                ;; offset=000EH
       488B45F8             mov      rax, qword ptr [rbp-08H]
       488B00               mov      rax, qword ptr [rax]

G_M000_IG03:                ;; offset=0015H
       4883C410             add      rsp, 16
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 27

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Abort trap: 6

macos-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - MacOS
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Abort trap: 6

linux-x64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Unix
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       4883EC10             sub      rsp, 16
       488D6C2410           lea      rbp, [rsp+10H]
       48897DF8             mov      qword ptr [rbp-08H], rdi

G_M000_IG02:                ;; offset=000EH
       488B45F8             mov      rax, qword ptr [rbp-08H]
       488B00               mov      rax, qword ptr [rax]

G_M000_IG03:                ;; offset=0015H
       4883C410             add      rsp, 16
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 27

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])

linux-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - Unix
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Aborted (core dumped)

windows-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - Windows
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])

Nevertheless it works on windows-x64, here is its disasm:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       488BEC               mov      rbp, rsp
       48894D10             mov      bword ptr [rbp+10H], rcx
       48895518             mov      qword ptr [rbp+18H], rdx
 
G_M000_IG02:                ;; offset=000CH
       488B4518             mov      rax, qword ptr [rbp+18H]
       488B5510             mov      rdx, bword ptr [rbp+10H]
       8B08                 mov      ecx, dword ptr [rax]
       890A                 mov      dword ptr [rdx], ecx
       8B4802               mov      ecx, dword ptr [rax+02H]
       894A02               mov      dword ptr [rdx+02H], ecx
       488B4510             mov      rax, bword ptr [rbp+10H]
 
G_M000_IG03:                ;; offset=0022H
       5D                   pop      rbp
       C3                   ret      
 
; Total bytes of code 36

Linked issues: #76194.

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Nov 12, 2022
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Nov 12, 2022
@ghost
Copy link

ghost commented Nov 12, 2022

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

Issue Details

Hi!

I faced with System.AccessViolationException when reading 6-byte structure in .NET 7 app on Windows ARM64, Linux x64/ARM64, and macOS x64/ARM64, here is demo app:

using System.IO.MemoryMappedFiles;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace unaligned_access_deref_csharp
{
    internal class Program
    {
        [StructLayout(LayoutKind.Sequential, Pack = 1, Size = 6)]
        public struct Data
        {
            public UInt32 U32;

            public UInt16 U16;
        }

        static unsafe Data deref(byte* pdata)
        {
            return *(Data*)(pdata);
        }
        
        static unsafe void Main(string[] args)
        {
            var mappedFile = MemoryMappedFile.CreateNew(null, 0x4000);
            var viewAccessor = mappedFile.CreateViewAccessor();
            byte* viewPtr = null;
            viewAccessor.SafeMemoryMappedViewHandle.AcquirePointer(ref viewPtr);
            Unsafe.InitBlock(viewPtr, 0x01, (uint)viewAccessor.Capacity);

            _ = deref(viewPtr + viewAccessor.Capacity - Unsafe.SizeOf<Data>());
        }
    }
}

I tried it using .NET SDK 7.0.100 on different platforms, the results are as follows (w/ COMPlus_JitDisasm enabled):

macos-x64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Unix
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       4883EC10             sub      rsp, 16
       488D6C2410           lea      rbp, [rsp+10H]
       48897DF8             mov      qword ptr [rbp-08H], rdi

G_M000_IG02:                ;; offset=000EH
       488B45F8             mov      rax, qword ptr [rbp-08H]
       488B00               mov      rax, qword ptr [rax]

G_M000_IG03:                ;; offset=0015H
       4883C410             add      rsp, 16
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 27

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Abort trap: 6

macos-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - MacOS
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Abort trap: 6

linux-x64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Unix
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       4883EC10             sub      rsp, 16
       488D6C2410           lea      rbp, [rsp+10H]
       48897DF8             mov      qword ptr [rbp-08H], rdi

G_M000_IG02:                ;; offset=000EH
       488B45F8             mov      rax, qword ptr [rbp-08H]
       488B00               mov      rax, qword ptr [rax]

G_M000_IG03:                ;; offset=0015H
       4883C410             add      rsp, 16
       5D                   pop      rbp
       C3                   ret

; Total bytes of code 27

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])

linux-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - Unix
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])
Aborted (core dumped)

windows-arm64:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for generic ARM64 CPU - Windows
; Tier-0 compilation
; MinOpts code
; fp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
        A9BE7BFD          stp     fp, lr, [sp,#-0x20]!
        910003FD          mov     fp, sp
        F9000FA0          str     x0, [fp,#0x18]

G_M000_IG02:                ;; offset=000CH
        F9400FA0          ldr     x0, [fp,#0x18]
        F9400000          ldr     x0, [x0]

G_M000_IG03:                ;; offset=0014H
        A8C27BFD          ldp     fp, lr, [sp],#0x20
        D65F03C0          ret     lr

; Total bytes of code 28

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
   at unaligned_access_deref_csharp.Program.deref(Byte*)
   at unaligned_access_deref_csharp.Program.Main(System.String[])

Nevertheless it works on windows-x64, here is its disasm:

; Assembly listing for method unaligned_access_deref_csharp.Program:deref(ulong):Data
; Emitting BLENDED_CODE for X64 CPU with AVX - Windows
; Tier-0 compilation
; MinOpts code
; rbp based frame
; partially interruptible

G_M000_IG01:                ;; offset=0000H
       55                   push     rbp
       488BEC               mov      rbp, rsp
       48894D10             mov      bword ptr [rbp+10H], rcx
       48895518             mov      qword ptr [rbp+18H], rdx
 
G_M000_IG02:                ;; offset=000CH
       488B4518             mov      rax, qword ptr [rbp+18H]
       488B5510             mov      rdx, bword ptr [rbp+10H]
       8B08                 mov      ecx, dword ptr [rax]
       890A                 mov      dword ptr [rdx], ecx
       8B4802               mov      ecx, dword ptr [rax+02H]
       894A02               mov      dword ptr [rdx+02H], ecx
       488B4510             mov      rax, bword ptr [rbp+10H]
 
G_M000_IG03:                ;; offset=0022H
       5D                   pop      rbp
       C3                   ret      
 
; Total bytes of code 36

Linked issues: #76194.

Author: k15tfu
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@SingleAccretion SingleAccretion added this to the 8.0.0 milestone Nov 12, 2022
@ghost ghost removed the untriaged New issue has not been triaged by the area owner label Nov 12, 2022
@SingleAccretion
Copy link
Contributor

Same problem as #76194.

@k15tfu
Copy link
Contributor Author

k15tfu commented Nov 12, 2022

Please note that unlike #76194 it also appears on different platforms (Windows, Linux, macOS) and architectures, and does not use Unsafe.ReadUnaligned.

@SingleAccretion
Copy link
Contributor

It is expected we will see this bug on cited platforms, since their ABIs (unlike, say, Unix x86 or Windows x64) call for returning structs 3, 5, 6, 7 bytes in size in a single register.

@EgorBo
Copy link
Member

EgorBo commented Nov 12, 2022

This and a similar bug existed in .NET since like .NET Framework 3.5 I think, it's just that MemoryMappedFile API didn't exist back then so developers could only hit it with some manual VirtualAlloc/mmap pinvokes. I'll rebase the fix

@MichalPetryka
Copy link
Contributor

Please note that unlike #76194 it also appears on different platforms (Windows, Linux, macOS) and architectures, and does not use Unsafe.ReadUnaligned.

Unsafe.ReadUnaligned is a no-op on platforms that support unaligned loads (such as x64 and AMR64) so it most likely doesn't matter here.

@EgorBo
Copy link
Member

EgorBo commented Nov 17, 2022

Fixed with #76341

@EgorBo EgorBo closed this as completed Nov 17, 2022
@ghost ghost locked as resolved and limited conversation to collaborators Dec 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

No branches or pull requests

4 participants