FEXCore/Allocator: Don't hang when /proc/self/maps can't be opened

StealMemoryRegion guards the open() with LogMan::Throw::AFmt, which
compiles out in release builds. With no procfs mounted the fd is -1 and
CollectMemoryGaps then loops on read(-1) forever at 100% CPU.

This is hit whenever FEX is the x86_64 binfmt handler and something runs
an x86 binary in a root without /proc. BuildKit does exactly that: its
emulator probe execs a static x86_64 binary in an empty chroot, so every
BuildKit start on an Arm host with FEX registered hangs.

Reserve nothing instead: StealMemoryRegion returns no regions and
Setup48BitAllocatorIfExists skips the 48-bit allocator. The guest then
runs without the upper VA hidden, which only matters in environments
that previously never got past startup.
This commit is contained in:
Nick Rogers committed 2026-09-30 14:43:05 +01:00
1 parent 0df84d3844
commit 6b43daccf0
1 file changed
+9 -1
+9 -1
View File
@@ -218,7 +218,12 @@ fextl::vector<MemoryRegion> StealMemoryRegion(uintptr_t Begin, uintptr_t End) {
const uintptr_t StackLocation_u64 = reinterpret_cast<uintptr_t>(alloca(0));
const int MapsFD = open("/proc/self/maps", O_RDONLY);
LogMan::Throw::AFmt(MapsFD != -1, "Failed to open /proc/self/maps");
if (MapsFD == -1) {
// No procfs, as in BuildKit's emulator probe (an empty chroot). The assert
// above it compiles out in release, and CollectMemoryGaps then spins on
// read(-1) forever; reserve nothing instead.
return {};
}
auto Regions = CollectMemoryGaps(Begin, End, MapsFD);
close(MapsFD);
@@ -282,6 +287,9 @@ fextl::vector<MemoryRegion> Setup48BitAllocatorIfExists(size_t PageSize) {
uintptr_t Begin48BitVA = 0x0'8000'0000'0000ULL;
uintptr_t End48BitVA = 0x1'0000'0000'0000ULL;
auto Regions = StealMemoryRegion(Begin48BitVA, End48BitVA);
if (Regions.empty()) {
return {};
}
Alloc64 = Alloc::OSAllocator::Create64BitAllocatorWithRegions(Regions);
AssignHookOverrides(PageSize);