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

System.OutOfMemoryException when allocating jump stub on macOS ARM64 #83818

Closed
k15tfu opened this issue Mar 23, 2023 · 1 comment · Fixed by #83819 or #84023
Closed

System.OutOfMemoryException when allocating jump stub on macOS ARM64 #83818

k15tfu opened this issue Mar 23, 2023 · 1 comment · Fixed by #83819 or #84023

Comments

@k15tfu
Copy link
Contributor

k15tfu commented Mar 23, 2023

Hi!

Sometimes I get a System.OutOfMemoryException exception in .NET 7 app on macOS ARM64 in arbitrary places like:

System.OutOfMemoryException
at InvokeStub_ContextConsumersWithAttributesManager..ctor(Object, Object, IntPtr*)
at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)

Digging into this, it turned out that the exception is thrown from HostCodeHeap::InitializeHeapList():

pTracker = AllocMemory_NoThrow(0, JUMP_ALLOCATE_SIZE, sizeof(void*), 0);
if (pTracker == NULL)
{
// This should only ever happen with fault injection
_ASSERTE(g_pConfig->ShouldInjectFault(INJECTFAULT_DYNAMICCODEHEAP));
delete pHp;
ThrowOutOfMemory();
}

because ExecutableAllocator::Commit() failed to commit executable memory:

if (NULL == ExecutableAllocator::Instance()->Commit(m_pLastAvailableCommittedAddr, sizeToCommit, true /* isExecutable */))
{
LOG((LF_BCL, LL_ERROR, "CodeHeap [0x%p] - VirtualAlloc failed\n", this));
return NULL;
}

On macOS ARM64 ExecutableAllocator::IsDoubleMappingEnabled() is disabled, thus it internally calls VirtualAlloc(..., MEM_COMMIT, PAGE_EXECUTE_READWRITE) for the pre-reserved memory HostCodeHeap::m_pLastAvailableCommittedAddr, but then mprotect(..., PROT_EXEC | PROT_READ | PROT_WRITE) fails with errno EACCES (aka Permission denied):

if (protectionState != vProtect)
{
// Change permissions.
if (mprotect((void *) StartBoundary, MemSize, nProtect) != -1)
{
memset(pInformation->pProtectionState + runStart,
vProtect, runLength);
}
else
{
ERROR("mprotect() failed! Error(%d)=%s\n",
errno, strerror(errno));
goto error;
}
}

because initially this memory region was reserved w/o MEM_RESERVE_EXECUTABLE flag (which is used for MAP_JIT):

if ((mbInfo.State == MEM_FREE) &&
(mbInfo.RegionSize >= (SIZE_T) dwSize || mbInfo.RegionSize == 0))
{
// Try reserving the memory using VirtualAlloc now
pResult = (BYTE*)ClrVirtualAlloc(tryAddr, dwSize, MEM_RESERVE, flProtect);
// Normally this will be successful
//
if (pResult != nullptr)
{
// return pResult
break;
}

despite the fact that ExecutableAllocator::ReserveWithinRange() actually requests it:

else
{
DWORD allocationType = MEM_RESERVE;
#ifdef HOST_UNIX
// Tell PAL to use the executable memory allocator to satisfy this request for virtual memory.
// This will allow us to place JIT'ed code close to the coreclr library
// and thus improve performance by avoiding jump stubs in managed code.
allocationType |= MEM_RESERVE_EXECUTABLE;
#endif
return ClrVirtualAllocWithinRange((const BYTE*)loAddress, (const BYTE*)hiAddress, size, allocationType, PAGE_NOACCESS);
}

Linked issues: #50391, #54954.

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Mar 23, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Mar 23, 2023
@k15tfu
Copy link
Contributor Author

k15tfu commented Mar 23, 2023

I have checked that the issue is gone if we use MEM_RESERVE_EXECUTABLE flag, here is a draft PR #83819.

cc @janvorli

k15tfu added a commit to k15tfu/runtime that referenced this issue Mar 24, 2023
janvorli pushed a commit that referenced this issue Mar 24, 2023
@ghost ghost removed in-pr There is an active PR which will close this issue when it is merged untriaged New issue has not been triaged by the area owner labels Mar 24, 2023
github-actions bot pushed a commit that referenced this issue Mar 27, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Mar 28, 2023
k15tfu added a commit to k15tfu/runtime that referenced this issue Mar 28, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Mar 28, 2023
AaronRobinsonMSFT pushed a commit that referenced this issue Apr 10, 2023
…in ClrVirtualAllocWithinRange() (#83958)

* Fix reserving executable memory as per allocation type in ClrVirtualAllocWithinRange()

Fixes #83818

---------

Co-authored-by: Ilia K <ki.stfu@gmail.com>
Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com>
@ghost ghost locked as resolved and limited conversation to collaborators Apr 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
1 participant