diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76194/CMakeLists.txt b/src/tests/JIT/Regression/JitBlue/Runtime_76194/CMakeLists.txt new file mode 100644 index 00000000000000..2cdee0de43a7a6 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76194/CMakeLists.txt @@ -0,0 +1,3 @@ +include_directories(${INC_PLATFORM_DIR}) +add_library(CrossplatVirtualAlloc SHARED CrossplatVirtualAlloc.cpp) +target_link_libraries(CrossplatVirtualAlloc PRIVATE platformdefines) diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76194/CrossplatVirtualAlloc.cpp b/src/tests/JIT/Regression/JitBlue/Runtime_76194/CrossplatVirtualAlloc.cpp new file mode 100644 index 00000000000000..c0b1be74b6947b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76194/CrossplatVirtualAlloc.cpp @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#ifdef _WIN32 +#include +#else +#include +#endif + +extern "C" DLL_EXPORT void* AllocWithGuard(uintptr_t size) +{ +#ifdef _WIN32 + void* reservePtr = VirtualAlloc(nullptr, size * 2, MEM_RESERVE, PAGE_READWRITE); + if (reservePtr != nullptr) + { + void* ptr = VirtualAlloc(reservePtr, size, MEM_COMMIT, PAGE_READWRITE); + if (ptr == nullptr) + { + VirtualFree(reservePtr, 0, MEM_RELEASE); + } + return ptr; + } +#else + uint8_t* ptr = (uint8_t*)mmap(nullptr, size * 2, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ptr != MAP_FAILED) + { + if (mprotect(ptr + size, size, PROT_NONE) == 0) + { + return ptr; + } + munmap(ptr, size * 2); + } +#endif + return nullptr; +} + +extern "C" DLL_EXPORT void Free(void* ptr, uintptr_t size) +{ +#ifdef _WIN32 + VirtualFree(ptr, 0, MEM_RELEASE); +#else + munmap(ptr, size * 2); +#endif +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.cs b/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.cs index 7933fa9f80493f..b81008112e3793 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.cs +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.cs @@ -53,116 +53,46 @@ public struct Data5 [MethodImpl(MethodImplOptions.NoInlining)] static void Write5(byte* location, Data5 d) => Unsafe.WriteUnaligned(location, d); + [MethodImpl(MethodImplOptions.NoInlining)] + public static byte* GetPointerNearPageEndFor(byte* ptr, nuint pageSize) => ptr + pageSize - Unsafe.SizeOf(); + + [MethodImpl(MethodImplOptions.NoInlining)] public static int Main() { - if (!OperatingSystem.IsWindows() && !OperatingSystem.IsLinux()) - { - return 100; - } - + nuint pageSize = (nuint)Environment.SystemPageSize; for (int i = 0; i < 100; i++) { - using CrossVirtualAlloc alloc = new(); - if (alloc.IsFailedToCommit) + byte* ptr = CrossplatVirtualAlloc.AllocWithGuard(pageSize); + if (ptr == null) { - Console.WriteLine("VirtualAlloc/mmap/mprotect failed, giving up on test."); - break; + throw new InvalidOperationException($"CrossplatVirtualAlloc.Alloc returned null at {i}th iteration"); } - Read1(alloc.GetPointerNearPageEndFor()); - Write1(alloc.GetPointerNearPageEndFor(), default); - Read2(alloc.GetPointerNearPageEndFor()); - Write2(alloc.GetPointerNearPageEndFor(), default); - Read3(alloc.GetPointerNearPageEndFor()); - Write3(alloc.GetPointerNearPageEndFor(), default); - Read4(alloc.GetPointerNearPageEndFor()); - Write4(alloc.GetPointerNearPageEndFor(), default); - Read5(alloc.GetPointerNearPageEndFor()); - Write5(alloc.GetPointerNearPageEndFor(), default); + + Read1(GetPointerNearPageEndFor(ptr, pageSize)); + Write1(GetPointerNearPageEndFor(ptr, pageSize), default); + Read2(GetPointerNearPageEndFor(ptr, pageSize)); + Write2(GetPointerNearPageEndFor(ptr, pageSize), default); + Read3(GetPointerNearPageEndFor(ptr, pageSize)); + Write3(GetPointerNearPageEndFor(ptr, pageSize), default); + Read4(GetPointerNearPageEndFor(ptr, pageSize)); + Write4(GetPointerNearPageEndFor(ptr, pageSize), default); + Read5(GetPointerNearPageEndFor(ptr, pageSize)); + Write5(GetPointerNearPageEndFor(ptr, pageSize), default); + + CrossplatVirtualAlloc.Free(ptr, pageSize); } return 100; } - - [MethodImpl(MethodImplOptions.NoInlining)] - static T Read(byte* location) => Unsafe.ReadUnaligned(location); - - [MethodImpl(MethodImplOptions.NoInlining)] - static void Write(byte* location, T t) => Unsafe.WriteUnaligned(location, t); } // Cross-platform implementation of VirtualAlloc that is focused on reproducing problems // where JIT emits code that reads/writes more than requested -public unsafe class CrossVirtualAlloc : IDisposable +internal static unsafe class CrossplatVirtualAlloc { - private readonly byte* _ptr; - - public CrossVirtualAlloc() - { - if (OperatingSystem.IsWindows()) - { - const int MEM_COMMIT = 0x1000; - const int MEM_RESERVE = 0x2000; - const int PAGE_READWRITE = 0x04; - const int MEM_RELEASE = 0x8000; - - byte* reservePtr = VirtualAlloc(null, PageSize * 2, MEM_RESERVE, PAGE_READWRITE); - if (reservePtr != null) - { - _ptr = VirtualAlloc(reservePtr, PageSize, MEM_COMMIT, PAGE_READWRITE); - if (_ptr == null) - { - VirtualFree(reservePtr, 0, MEM_RELEASE); - } - } - } - else - { - const int PROT_NONE = 0x0; - const int PROT_READ = 0x1; - const int PROT_WRITE = 0x2; - const int MAP_PRIVATE = 0x02; - const int MAP_ANONYMOUS = 0x20; - - _ptr = mmap(null, 2 * PageSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (_ptr != null && mprotect(_ptr + PageSize, PageSize, PROT_NONE) != 0) - { - munmap(_ptr, 2 * PageSize); - } - } - } - - public bool IsFailedToCommit => _ptr == null; - - public nuint PageSize => (nuint)Environment.SystemPageSize; - - [MethodImpl(MethodImplOptions.NoInlining)] - public byte* GetPointerNearPageEndFor() => _ptr + PageSize - Unsafe.SizeOf(); - - public void Dispose() - { - if (OperatingSystem.IsWindows()) - { - const int MEM_RELEASE = 0x8000; - VirtualFree(_ptr, 0, MEM_RELEASE); - } - else - { - munmap(_ptr, (nuint)Environment.SystemPageSize * 2); - } - } - - [DllImport("kernel32")] - static extern byte* VirtualAlloc(byte* lpAddress, nuint dwSize, uint flAllocationType, uint flProtect); - - [DllImport("kernel32")] - static extern int VirtualFree(byte* lpAddress, nuint dwSize, uint dwFreeType); - - [DllImport("libc")] - static extern byte* mmap(byte* addr, nuint length, int prot, int flags, int fd, nuint offset); - - [DllImport("libc")] - static extern int mprotect(byte* addr, nuint len, int prot); + [DllImport(nameof(CrossplatVirtualAlloc))] + public static extern byte* AllocWithGuard(nuint size); - [DllImport("libc")] - static extern int munmap(byte* addr, nuint length); + [DllImport(nameof(CrossplatVirtualAlloc))] + public static extern void Free(byte* ptr, nuint size); } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.csproj index 0f9eec3d705fb2..62151de2657f2c 100644 --- a/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.csproj +++ b/src/tests/JIT/Regression/JitBlue/Runtime_76194/Runtime_76194.csproj @@ -5,6 +5,7 @@ True + - \ No newline at end of file + diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 07db2c1b26b0b8..b43592b57fe8c3 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -3079,6 +3079,9 @@ Needs coreclr build + + Needs coreclr build + Needs coreclr build @@ -3460,6 +3463,9 @@ needs triage + + needs triage + https://github.com/dotnet/runtime/issues/41472 @@ -3847,6 +3853,9 @@ https://github.com/dotnet/runtime/issues/54906 + + https://github.com/dotnet/runtime/issues/54906 + https://github.com/dotnet/runtime/issues/54906 @@ -3953,6 +3962,9 @@ System.DllNotFoundException: GCPollNative + + System.DllNotFoundException: CrossplatVirtualAlloc + System.ArgumentNullException: Value cannot be null. (Parameter 'path1')