From 1c15454309a144af6a0a9037fdba670e6a5848a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Tue, 27 May 2025 15:06:18 +0200 Subject: [PATCH 1/7] Distinguish OOM and failure to reprotect in thunks APIs Resolves #113114. I wasn't sure how much cleanup to do here, the failure handling is a bit odd, I assume for historical reasons. --- .../nativeaot/Runtime/ThunksMapping.cpp | 10 +++- src/coreclr/nativeaot/Runtime/portable.cpp | 3 +- .../Runtime/Augments/RuntimeAugments.cs | 9 ++-- .../src/System/Runtime/RuntimeImports.cs | 2 +- .../src/System/Runtime/ThunkPool.cs | 52 ++++++++----------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp index f3abfb5f0a77c7..9b2a2faeb24634 100644 --- a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp +++ b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp @@ -100,13 +100,18 @@ FCIMPL0(int, RhpGetThunkBlockSize) } FCIMPLEND -EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() +EXTERN_C void* QCALLTYPE RhAllocateThunksMapping(int* isOOM) { + *isOOM = 0; + #ifdef WIN32 void * pNewMapping = PalVirtualAlloc(THUNKS_MAP_SIZE * 2, PAGE_READWRITE); if (pNewMapping == NULL) + { + *isOOM = 1; return NULL; + } void * pThunksSection = pNewMapping; void * pDataSection = (uint8_t*)pNewMapping + THUNKS_MAP_SIZE; @@ -120,7 +125,10 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() // changed anymore. void * pNewMapping = PalVirtualAlloc(THUNKS_MAP_SIZE * 2, PAGE_EXECUTE_READ); if (pNewMapping == NULL) + { + *isOOM = 1; return NULL; + } void * pThunksSection = pNewMapping; void * pDataSection = (uint8_t*)pNewMapping + THUNKS_MAP_SIZE; diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index ec992bc0ac4708..24a7b061a34520 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -365,8 +365,9 @@ FCIMPL2(Object *, RhpCheckedXchg, Object ** location, Object * value) } FCIMPLEND -FCIMPL0(void*, RhAllocateThunksMapping) +FCIMPL1(void*, RhAllocateThunksMapping, int * isOOM) { + *isOOM = 0; return NULL; } FCIMPLEND diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index a473c80470f6fc..da50b1e8901483 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -711,17 +711,14 @@ public static string TryGetMethodDisplayStringFromIp(IntPtr ip) public static object CreateThunksHeap(IntPtr commonStubAddress) { - object? newHeap = ThunksHeap.CreateThunksHeap(commonStubAddress); - if (newHeap == null) - throw new OutOfMemoryException(); - return newHeap; + return ThunksHeap.CreateThunksHeap(commonStubAddress); } public static IntPtr AllocateThunk(object thunksHeap) { - IntPtr newThunk = ((ThunksHeap)thunksHeap).AllocateThunk(); + IntPtr newThunk = ((ThunksHeap)thunksHeap).AllocateThunk(out Exception exception); if (newThunk == IntPtr.Zero) - throw new OutOfMemoryException(); + throw exception; return newThunk; } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index fcd46519f2de4b..bcb6e0ce2b70ef 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -358,7 +358,7 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary) internal static extern int RhpGetThunkBlockSize(); [LibraryImport(RuntimeLibrary, EntryPoint = "RhAllocateThunksMapping")] - internal static partial IntPtr RhAllocateThunksMapping(); + internal static unsafe partial IntPtr RhAllocateThunksMapping(int* isOOM); // // calls to runtime for type equality checks diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs index fcfee9b11342f8..fc32564e95c1de 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs @@ -87,11 +87,7 @@ private unsafe ThunksHeap(IntPtr commonStubAddress) _allocatedBlocks = new AllocatedBlock(); - IntPtr thunkStubsBlock; - lock (this) - { - thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(); - } + IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(out Exception ex); if (thunkStubsBlock != IntPtr.Zero) { @@ -110,20 +106,15 @@ private unsafe ThunksHeap(IntPtr commonStubAddress) _allocatedBlocks._blockBaseAddress = thunkStubsBlock; } - } - - public static unsafe ThunksHeap? CreateThunksHeap(IntPtr commonStubAddress) - { - try + else { - ThunksHeap newHeap = new ThunksHeap(commonStubAddress); - - if (newHeap._nextAvailableThunkPtr != IntPtr.Zero) - return newHeap; + throw ex; } - catch (Exception) { } + } - return null; + public static unsafe ThunksHeap CreateThunksHeap(IntPtr commonStubAddress) + { + return new ThunksHeap(commonStubAddress); } // TODO: Feature @@ -134,7 +125,7 @@ private unsafe ThunksHeap(IntPtr commonStubAddress) // // Note: Expected to be called under lock // - private unsafe bool ExpandHeap() + private unsafe bool ExpandHeap(out Exception exception) { AllocatedBlock newBlockInfo; @@ -142,12 +133,13 @@ private unsafe bool ExpandHeap() { newBlockInfo = new AllocatedBlock(); } - catch (Exception) + catch (Exception ex) { + exception = ex; return false; } - IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(); + IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(out exception); if (thunkStubsBlock != IntPtr.Zero) { @@ -177,13 +169,15 @@ private unsafe bool ExpandHeap() return false; } - public unsafe IntPtr AllocateThunk() + public unsafe IntPtr AllocateThunk(out Exception exception) { // TODO: optimize the implementation and make it lock-free // or at least change it to a per-heap lock instead of a global lock. Debug.Assert(_nextAvailableThunkPtr != IntPtr.Zero); + exception = null; + IntPtr nextAvailableThunkPtr; lock (this) { @@ -192,7 +186,7 @@ public unsafe IntPtr AllocateThunk() if (nextNextAvailableThunkPtr == IntPtr.Zero) { - if (!ExpandHeap()) + if (!ExpandHeap(out exception)) { return IntPtr.Zero; } @@ -331,9 +325,10 @@ internal static class ThunkBlocks private static IntPtr[] s_currentlyMappedThunkBlocks = new IntPtr[Constants.NumThunkBlocksPerMapping]; private static int s_currentlyMappedThunkBlocksIndex = Constants.NumThunkBlocksPerMapping; - public static unsafe IntPtr GetNewThunksBlock() + public static unsafe IntPtr GetNewThunksBlock(out Exception exception) { IntPtr nextThunksBlock; + exception = null; // Check the most recently mapped thunks block. Each mapping consists of multiple // thunk stubs pages, and multiple thunk data pages (typically 8 pages of each in a single mapping) @@ -347,16 +342,15 @@ public static unsafe IntPtr GetNewThunksBlock() } else { - nextThunksBlock = RuntimeImports.RhAllocateThunksMapping(); + int isOOM = 0; + nextThunksBlock = RuntimeImports.RhAllocateThunksMapping(&isOOM); if (nextThunksBlock == IntPtr.Zero) { - // We either ran out of memory and can't do anymore mappings of the thunks templates sections, - // or we are using the managed runtime services fallback, which doesn't provide the - // file mapping feature (ex: older version of mrt100.dll, or no mrt100.dll at all). - - // The only option is for the caller to attempt and recycle unused thunks to be able to - // find some free entries. + if (isOOM == 0) + exception = new NotSupportedException(); + else + exception = new OutOfMemoryException(); return IntPtr.Zero; } From eda2d1d4cbe3a6f4b332f676051641ed633f8de5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Wed, 28 May 2025 11:11:54 +0200 Subject: [PATCH 2/7] Rework exception throws --- src/coreclr/nativeaot/Runtime/CommonMacros.h | 1 + .../nativeaot/Runtime/ThunksMapping.cpp | 17 ++- src/coreclr/nativeaot/Runtime/portable.cpp | 5 +- .../Runtime/Augments/RuntimeAugments.cs | 5 +- .../src/System/Runtime/RuntimeImports.cs | 2 +- .../src/System/Runtime/ThunkPool.cs | 110 ++++++------------ src/libraries/Common/src/System/HResults.cs | 1 + 7 files changed, 49 insertions(+), 92 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index c174b06f17ccd4..e78b16545a844c 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -352,6 +352,7 @@ typedef int32_t HRESULT; #define S_OK 0x0 #define E_FAIL 0x80004005 +#define E_OUTOFMEMORY 0x8007000E #define UNREFERENCED_PARAMETER(P) (void)(P) #endif // !defined(_INC_WINDOWS) diff --git a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp index 9b2a2faeb24634..cf9ca087b9f9fe 100644 --- a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp +++ b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp @@ -100,17 +100,14 @@ FCIMPL0(int, RhpGetThunkBlockSize) } FCIMPLEND -EXTERN_C void* QCALLTYPE RhAllocateThunksMapping(int* isOOM) +EXTERN_C HRESULT QCALLTYPE RhAllocateThunksMapping(void** ppThunksSection) { - *isOOM = 0; - #ifdef WIN32 void * pNewMapping = PalVirtualAlloc(THUNKS_MAP_SIZE * 2, PAGE_READWRITE); if (pNewMapping == NULL) { - *isOOM = 1; - return NULL; + return E_OUTOFMEMORY; } void * pThunksSection = pNewMapping; @@ -126,8 +123,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping(int* isOOM) void * pNewMapping = PalVirtualAlloc(THUNKS_MAP_SIZE * 2, PAGE_EXECUTE_READ); if (pNewMapping == NULL) { - *isOOM = 1; - return NULL; + return E_OUTOFMEMORY; } void * pThunksSection = pNewMapping; @@ -137,7 +133,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping(int* isOOM) !PalVirtualProtect(pThunksSection, THUNKS_MAP_SIZE, PAGE_EXECUTE_READWRITE)) { PalVirtualFree(pNewMapping, THUNKS_MAP_SIZE * 2); - return NULL; + return E_FAIL; } #if defined(HOST_APPLE) && defined(HOST_ARM64) @@ -314,13 +310,14 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping(int* isOOM) if (!PalVirtualProtect(pThunksSection, THUNKS_MAP_SIZE, PAGE_EXECUTE_READ)) { PalVirtualFree(pNewMapping, THUNKS_MAP_SIZE * 2); - return NULL; + return E_FAIL; } #endif PalFlushInstructionCache(pThunksSection, THUNKS_MAP_SIZE); - return pThunksSection; + *ppThunksSection = pThunksSection; + return S_OK; } // FEATURE_RX_THUNKS diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index 24a7b061a34520..e3ea89d7ec3b0c 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -365,10 +365,9 @@ FCIMPL2(Object *, RhpCheckedXchg, Object ** location, Object * value) } FCIMPLEND -FCIMPL1(void*, RhAllocateThunksMapping, int * isOOM) +FCIMPL1(HRESULT, RhAllocateThunksMapping, void ** ppThunksSection) { - *isOOM = 0; - return NULL; + return S_FAIL; } FCIMPLEND diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs index da50b1e8901483..c55d468a4d4c8e 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs @@ -716,10 +716,7 @@ public static object CreateThunksHeap(IntPtr commonStubAddress) public static IntPtr AllocateThunk(object thunksHeap) { - IntPtr newThunk = ((ThunksHeap)thunksHeap).AllocateThunk(out Exception exception); - if (newThunk == IntPtr.Zero) - throw exception; - return newThunk; + return ((ThunksHeap)thunksHeap).AllocateThunk(); } public static void FreeThunk(object thunksHeap, IntPtr thunkAddress) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs index bcb6e0ce2b70ef..177d8440facd26 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/RuntimeImports.cs @@ -358,7 +358,7 @@ internal static IntPtr RhHandleAllocDependent(object primary, object secondary) internal static extern int RhpGetThunkBlockSize(); [LibraryImport(RuntimeLibrary, EntryPoint = "RhAllocateThunksMapping")] - internal static unsafe partial IntPtr RhAllocateThunksMapping(int* isOOM); + internal static unsafe partial int RhAllocateThunksMapping(IntPtr* ppMapping); // // calls to runtime for type equality checks diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs index fc32564e95c1de..802c18a743f494 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs @@ -87,29 +87,21 @@ private unsafe ThunksHeap(IntPtr commonStubAddress) _allocatedBlocks = new AllocatedBlock(); - IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(out Exception ex); + IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(); + IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock); - if (thunkStubsBlock != IntPtr.Zero) - { - IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock); - - // Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned) - Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0); + // Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned) + Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0); - // Update the last pointer value in the thunks data section with the value of the common stub address - *(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = commonStubAddress; - Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == commonStubAddress); + // Update the last pointer value in the thunks data section with the value of the common stub address + *(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = commonStubAddress; + Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == commonStubAddress); - // Set the head and end of the linked list - _nextAvailableThunkPtr = thunkDataBlock; - _lastThunkPtr = _nextAvailableThunkPtr + Constants.ThunkDataSize * (Constants.NumThunksPerBlock - 1); + // Set the head and end of the linked list + _nextAvailableThunkPtr = thunkDataBlock; + _lastThunkPtr = _nextAvailableThunkPtr + Constants.ThunkDataSize * (Constants.NumThunksPerBlock - 1); - _allocatedBlocks._blockBaseAddress = thunkStubsBlock; - } - else - { - throw ex; - } + _allocatedBlocks._blockBaseAddress = thunkStubsBlock; } public static unsafe ThunksHeap CreateThunksHeap(IntPtr commonStubAddress) @@ -125,59 +117,39 @@ public static unsafe ThunksHeap CreateThunksHeap(IntPtr commonStubAddress) // // Note: Expected to be called under lock // - private unsafe bool ExpandHeap(out Exception exception) + private unsafe void ExpandHeap() { - AllocatedBlock newBlockInfo; + AllocatedBlock newBlockInfo = new AllocatedBlock(); - try - { - newBlockInfo = new AllocatedBlock(); - } - catch (Exception ex) - { - exception = ex; - return false; - } + IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(); + IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock); - IntPtr thunkStubsBlock = ThunkBlocks.GetNewThunksBlock(out exception); + // Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned) + Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0); - if (thunkStubsBlock != IntPtr.Zero) - { - IntPtr thunkDataBlock = RuntimeImports.RhpGetThunkDataBlockAddress(thunkStubsBlock); + // Update the last pointer value in the thunks data section with the value of the common stub address + *(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = _commonStubAddress; + Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == _commonStubAddress); - // Address of the first thunk data cell should be at the beginning of the thunks data block (page-aligned) - Debug.Assert(((nuint)(nint)thunkDataBlock % Constants.PageSize) == 0); + // Link the last entry in the old list to the first entry in the new list + *((IntPtr*)_lastThunkPtr) = thunkDataBlock; - // Update the last pointer value in the thunks data section with the value of the common stub address - *(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) = _commonStubAddress; - Debug.Assert(*(IntPtr*)(thunkDataBlock + (int)(Constants.PageSize - IntPtr.Size)) == _commonStubAddress); + // Update the pointer to the last entry in the list + _lastThunkPtr = *((IntPtr*)_lastThunkPtr) + Constants.ThunkDataSize * (Constants.NumThunksPerBlock - 1); - // Link the last entry in the old list to the first entry in the new list - *((IntPtr*)_lastThunkPtr) = thunkDataBlock; + newBlockInfo._blockBaseAddress = thunkStubsBlock; + newBlockInfo._nextBlock = _allocatedBlocks; - // Update the pointer to the last entry in the list - _lastThunkPtr = *((IntPtr*)_lastThunkPtr) + Constants.ThunkDataSize * (Constants.NumThunksPerBlock - 1); - - newBlockInfo._blockBaseAddress = thunkStubsBlock; - newBlockInfo._nextBlock = _allocatedBlocks; - - _allocatedBlocks = newBlockInfo; - - return true; - } - - return false; + _allocatedBlocks = newBlockInfo; } - public unsafe IntPtr AllocateThunk(out Exception exception) + public unsafe IntPtr AllocateThunk() { // TODO: optimize the implementation and make it lock-free // or at least change it to a per-heap lock instead of a global lock. Debug.Assert(_nextAvailableThunkPtr != IntPtr.Zero); - exception = null; - IntPtr nextAvailableThunkPtr; lock (this) { @@ -186,10 +158,7 @@ public unsafe IntPtr AllocateThunk(out Exception exception) if (nextNextAvailableThunkPtr == IntPtr.Zero) { - if (!ExpandHeap(out exception)) - { - return IntPtr.Zero; - } + ExpandHeap(); nextAvailableThunkPtr = _nextAvailableThunkPtr; nextNextAvailableThunkPtr = *((IntPtr*)(nextAvailableThunkPtr)); @@ -325,10 +294,9 @@ internal static class ThunkBlocks private static IntPtr[] s_currentlyMappedThunkBlocks = new IntPtr[Constants.NumThunkBlocksPerMapping]; private static int s_currentlyMappedThunkBlocksIndex = Constants.NumThunkBlocksPerMapping; - public static unsafe IntPtr GetNewThunksBlock(out Exception exception) + public static unsafe IntPtr GetNewThunksBlock() { IntPtr nextThunksBlock; - exception = null; // Check the most recently mapped thunks block. Each mapping consists of multiple // thunk stubs pages, and multiple thunk data pages (typically 8 pages of each in a single mapping) @@ -342,18 +310,12 @@ public static unsafe IntPtr GetNewThunksBlock(out Exception exception) } else { - int isOOM = 0; - nextThunksBlock = RuntimeImports.RhAllocateThunksMapping(&isOOM); - - if (nextThunksBlock == IntPtr.Zero) - { - if (isOOM == 0) - exception = new NotSupportedException(); - else - exception = new OutOfMemoryException(); - - return IntPtr.Zero; - } + nextThunksBlock = IntPtr.Zero; + int result = RuntimeImports.RhAllocateThunksMapping(&nextThunksBlock); + if (result == HResults.E_OUTOFMEMORY) + throw new OutOfMemoryException(); + else if (result != HResults.S_OK) + throw new NotSupportedException() { HResult = result }; // Each mapping consists of multiple blocks of thunk stubs/data pairs. Keep track of those // so that we do not create a new mapping until all blocks in the sections we just mapped are consumed diff --git a/src/libraries/Common/src/System/HResults.cs b/src/libraries/Common/src/System/HResults.cs index 858015f9c45163..eab2b4e9e55715 100644 --- a/src/libraries/Common/src/System/HResults.cs +++ b/src/libraries/Common/src/System/HResults.cs @@ -121,6 +121,7 @@ internal static partial class HResults internal const int E_HANDLE = unchecked((int)0x80070006); internal const int E_INVALIDARG = unchecked((int)0x80070057); internal const int E_NOTIMPL = unchecked((int)0x80004001); + internal const int E_OUTOFMEMORY = unchecked((int)0x8007000E); internal const int E_POINTER = unchecked((int)0x80004003); internal const int ERROR_MRM_MAP_NOT_FOUND = unchecked((int)0x80073B1F); internal const int ERROR_TIMEOUT = unchecked((int)0x800705B4); From d33f7b358e75ec75376ab25ecac7be674df0842e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 29 May 2025 08:01:53 +0200 Subject: [PATCH 3/7] FB --- .../nativeaot/Runtime/ThunksMapping.cpp | 20 ++++++++++--------- src/coreclr/nativeaot/Runtime/portable.cpp | 2 +- .../src/System/Runtime/ThunkPool.cs | 2 +- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp index cf9ca087b9f9fe..11f38b82986e9b 100644 --- a/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp +++ b/src/coreclr/nativeaot/Runtime/ThunksMapping.cpp @@ -332,7 +332,7 @@ FCDECL0(int, RhpGetThunkBlockSize); FCDECL1(void*, RhpGetThunkDataBlockAddress, void* addr); FCDECL1(void*, RhpGetThunkStubsBlockAddress, void* addr); -EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() +EXTERN_C HRESULT QCALLTYPE RhAllocateThunksMapping(void** ppThunksSection) { static int nextThunkDataMapping = 0; @@ -347,7 +347,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() if (nextThunkDataMapping == thunkDataMappingCount) { - return NULL; + return E_FAIL; } if (g_pThunkStubData == NULL) @@ -358,7 +358,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() if (g_pThunkStubData == NULL) { - return NULL; + return E_OUTOFMEMORY; } } @@ -366,7 +366,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() if (VirtualAlloc(pThunkDataBlock, thunkDataMappingSize, MEM_COMMIT, PAGE_READWRITE) == NULL) { - return NULL; + return E_OUTOFMEMORY; } nextThunkDataMapping++; @@ -374,7 +374,8 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() void* pThunks = RhpGetThunkStubsBlockAddress(pThunkDataBlock); ASSERT(RhpGetThunkDataBlockAddress(pThunks) == pThunkDataBlock); - return pThunks; + *ppThunksSection = pThunks; + return S_OK; } #else // FEATURE_FIXED_POOL_THUNKS @@ -385,7 +386,7 @@ FCDECL0(int, RhpGetNumThunksPerBlock); FCDECL0(int, RhpGetThunkSize); FCDECL0(int, RhpGetThunkBlockSize); -EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() +EXTERN_C HRESULT QCALLTYPE RhAllocateThunksMapping(void** ppThunksSection) { static void* pThunksTemplateAddress = NULL; @@ -414,7 +415,7 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() int templateRva = (int)((uint8_t*)RhpGetThunksBase() - pModuleBase); if (!PalAllocateThunksFromTemplate((HANDLE)pModuleBase, templateRva, templateSize, &pThunkMap)) - return NULL; + return E_OUTOFMEMORY; } if (!PalMarkThunksAsValidCallTargets( @@ -427,10 +428,11 @@ EXTERN_C void* QCALLTYPE RhAllocateThunksMapping() if (pThunkMap != pThunksTemplateAddress) PalFreeThunksFromTemplate(pThunkMap, templateSize); - return NULL; + return E_FAIL; } - return pThunkMap; + *ppThunksSection = pThunkMap; + return S_OK; } #endif // FEATURE_RX_THUNKS diff --git a/src/coreclr/nativeaot/Runtime/portable.cpp b/src/coreclr/nativeaot/Runtime/portable.cpp index e3ea89d7ec3b0c..3cfb34807ef72f 100644 --- a/src/coreclr/nativeaot/Runtime/portable.cpp +++ b/src/coreclr/nativeaot/Runtime/portable.cpp @@ -367,7 +367,7 @@ FCIMPLEND FCIMPL1(HRESULT, RhAllocateThunksMapping, void ** ppThunksSection) { - return S_FAIL; + return E_FAIL; } FCIMPLEND diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs index 802c18a743f494..93f1c8565600d5 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs @@ -315,7 +315,7 @@ public static unsafe IntPtr GetNewThunksBlock() if (result == HResults.E_OUTOFMEMORY) throw new OutOfMemoryException(); else if (result != HResults.S_OK) - throw new NotSupportedException() { HResult = result }; + throw new PlatformNotSupportedException(); // Each mapping consists of multiple blocks of thunk stubs/data pairs. Keep track of those // so that we do not create a new mapping until all blocks in the sections we just mapped are consumed From eee3e351addabef6d7d2b6524f8f09e2c30b4bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 29 May 2025 13:24:09 +0200 Subject: [PATCH 4/7] FB --- .../src/System/Runtime/ThunkPool.cs | 2 +- .../src/Resources/Strings.resx | 59 ++++++++++--------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs index 93f1c8565600d5..429513459ce250 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/ThunkPool.cs @@ -315,7 +315,7 @@ public static unsafe IntPtr GetNewThunksBlock() if (result == HResults.E_OUTOFMEMORY) throw new OutOfMemoryException(); else if (result != HResults.S_OK) - throw new PlatformNotSupportedException(); + throw new PlatformNotSupportedException(SR.PlatformNotSupported_DynamicEntrypoint); // Each mapping consists of multiple blocks of thunk stubs/data pairs. Keep track of those // so that we do not create a new mapping until all blocks in the sections we just mapped are consumed diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index 475d54061b4d0b..ea16db6230b4f8 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -1,17 +1,17 @@  - @@ -4361,4 +4361,7 @@ Creating an object wrapper for a COM instance with user state is not implemented. - + + Dynamic entrypoint allocation is not supported in the current environment. + + \ No newline at end of file From 0248f3100fdc5831a4656c70c692bb78084b1fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Thu, 29 May 2025 23:57:53 +0200 Subject: [PATCH 5/7] Add back HRESULT --- src/coreclr/nativeaot/Runtime/CommonMacros.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index a7e3dbd57cf651..e21e8fe4a63b93 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -341,6 +341,22 @@ extern uint64_t g_startupTimelineEvents[NUM_STARTUP_TIMELINE_EVENTS]; #define DECLSPEC_THREAD __thread #endif // !_MSC_VER +#ifndef __GCENV_BASE_INCLUDED__ +#if !defined(_INC_WINDOWS) +#ifdef _WIN32 +// this must exactly match the typedef used by windows.h +typedef long HRESULT; +#else +typedef int32_t HRESULT; +#endif + +#define S_OK 0x0 +#define E_FAIL 0x80004005 +#define E_OUTOFMEMORY 0x8007000E + +#endif // !defined(_INC_WINDOWS) +#endif // __GCENV_BASE_INCLUDED__ + // PAL Numbers // Used to ensure cross-compiler compatibility when declaring large // integer constants. 64-bit integer constants should be wrapped in the From 2f1e6ff222a2fbbb86b52fc89f0d8cbf3ed2cabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 30 May 2025 07:24:27 +0200 Subject: [PATCH 6/7] Revert "Add back HRESULT" This reverts commit 0248f3100fdc5831a4656c70c692bb78084b1fc0. --- src/coreclr/nativeaot/Runtime/CommonMacros.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/coreclr/nativeaot/Runtime/CommonMacros.h b/src/coreclr/nativeaot/Runtime/CommonMacros.h index e21e8fe4a63b93..a7e3dbd57cf651 100644 --- a/src/coreclr/nativeaot/Runtime/CommonMacros.h +++ b/src/coreclr/nativeaot/Runtime/CommonMacros.h @@ -341,22 +341,6 @@ extern uint64_t g_startupTimelineEvents[NUM_STARTUP_TIMELINE_EVENTS]; #define DECLSPEC_THREAD __thread #endif // !_MSC_VER -#ifndef __GCENV_BASE_INCLUDED__ -#if !defined(_INC_WINDOWS) -#ifdef _WIN32 -// this must exactly match the typedef used by windows.h -typedef long HRESULT; -#else -typedef int32_t HRESULT; -#endif - -#define S_OK 0x0 -#define E_FAIL 0x80004005 -#define E_OUTOFMEMORY 0x8007000E - -#endif // !defined(_INC_WINDOWS) -#endif // __GCENV_BASE_INCLUDED__ - // PAL Numbers // Used to ensure cross-compiler compatibility when declaring large // integer constants. 64-bit integer constants should be wrapped in the From 4c20081de792d35c21c0d68f59e209f645e8c342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Strehovsk=C3=BD?= Date: Fri, 30 May 2025 07:26:28 +0200 Subject: [PATCH 7/7] FB --- src/coreclr/nativeaot/Runtime/PalRedhawk.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/coreclr/nativeaot/Runtime/PalRedhawk.h b/src/coreclr/nativeaot/Runtime/PalRedhawk.h index 1c65ece5a185f4..9c430a168627e8 100644 --- a/src/coreclr/nativeaot/Runtime/PalRedhawk.h +++ b/src/coreclr/nativeaot/Runtime/PalRedhawk.h @@ -68,6 +68,10 @@ // we have to (in which case these definitions will move to CommonTypes.h). typedef int32_t HRESULT; +#define S_OK 0x0 +#define E_FAIL 0x80004005 +#define E_OUTOFMEMORY 0x8007000E + typedef WCHAR * LPWSTR; typedef const WCHAR * LPCWSTR; typedef char * LPSTR;