docs/ProgrammingConcerns.md
FEX-Emu needs to allocate memory differently than regular applications. This problem happens because FEX runs both 32-bit and 64-bit guest applications in the same address space as FEX itself. When running 32-bit applications, FEX reserves up all memory above 4GB in order to correctly emulate the 32-bit address space. We then use that reserved space for FEX allocations, so we don't interrupt application's own allocations.
We could control the placement of FEX's internal allocations by overriding the system allocator. However, 32-bit thunks (and their corresponding native host libraries) still need to allocate memory in the lower 4 GB of memory so that they produce guest-accessible pointers. Since overriding the system allocator is a global operation, selectively overriding it like this is not possible.
Since we found no way to resolve this conflict, we had to resort to the alternative of avoiding use of the system allocator for FEX's internal allocations entirely (where possible).
Most C++ APIs allow you to replace their allocators, but some don't and we need to avoid those APIs. If FEX uses them then the 32-bit application running might run out of memory. This isn't an all encompassing list and we will add to it as our CI captures more problems.
get_nprocs_confUse FEX::CPUInfo::CalculateNumberOfCPUs instead.
getcwdDon't use getcwd with a nullptr buffer. It will allocate memory behind our back and return a pointer that needs a free.
strerrorThis allocates and frees memory based on locale! Even with C local it'll attempt to free(0). FEX-Emu should avoid using this function and instead just return the number. If necessary FEX will provide its own routine for getting this string back.
std::make_uniqueUse fextl::make_unique instead.
std::unique_ptrUse fextl::unique_ptr instead.
std::filesystemThis namespace is /highly/ likely to allocate memory behind our back. FEX should avoid using this API as much as possible.
Use FHU::Filesystem::IsRelative instead.
Always allocates memory.
Use realpath instead.
Creates a std::filesystem::path when passing in to it.
Use FHU::Filesystem::Exists instead.
Always allocates memory.
Use realpath instead.
Use FHU::Filesystem::LexicallyNormal instead.
Creates a std::filesystem::path when passing in to it.
Use FHU::Filesystem::CreateDirectory and FHU::Filesystem::CreateDirectories instead.
Use FHU::Filesystem::ParentPath instead.
Use FHU::Filesystem::GetFilename instead.
Use FHU::Filesystem::CopyFile instead.
See GetTempFolder() in FEXServerClient.cpp (split/move to FHU::Filesystem if needed by other users).
FILE-based APIFILE always allocates memory and must be avoided.
Use a combination of raw FDs and fextl::string APIs instead.
<fstream> -> std::fstream<cstdio> -> std::fwritestd::stringUse fextl::string instead.
Use fextl::fmt::format instead.
std::stolstd::stoulstd::stollstd::stoullThese all consume a std::string as their first argument. Use the equivalent functions that don't use std::string
std::strtolstd::strtoulstd::strtollstd::strtoullfmt::fmt::formatUse fextl::fmt:: instead
getpwuid and getpwuid_rAllocates memory for parsing passwd and other files. One would assume getpwuid_r would use the buffer passed in, but nope glibc nss_database_get
allocates memory.
Don't use any of these APIs in FEXLoader/FEXInterpreter. Shoutout to this StackOverflow post for this huge list.
std::anystd::function and lambdasOne must take additional considerations when using these to ensure that they don't allocate memory. These don't have any way to replace which allocator is used for these objects. Additionally there is no way up-front to know if these will allocate memory or if the compiler will use small-function optimizations to avoid allocations. The only real way to check this is to enable the glibc faulting compile option.
std::function as an argument is unlikely to optimize away their memory allocations.std::valarraystd::filebufstd::inplace_merge<stdexcept>std::boyer_moore_searcherstd::filesystem::pathstd::filesystem::directory_iteratorstd::regexstd::threadstd::asyncstd::packaged_taskstd::promise<iostream>Don't use these directly as they will the glibc allocator.
Use FEXCore::Allocator::mmap
Use FEXCore::Allocator::munmap
Use FEXCore::Allocator::malloc
Use FEXCore::Allocator::calloc
Use FEXCore::Allocator::memalign
Use FEXCore::Allocator::valloc
Use FEXCore::Allocator::posix_memalign
Use FEXCore::Allocator::realloc
Use FEXCore::Allocator::free
Use FEXCore::Allocator::aligned_alloc
!! DO NOT USE !!
FEX has the cmake option ENABLE_GLIBC_ALLOCATOR_HOOK_FAULT to hook in to glibc's allocator and fault if anything is allocating through it.
This can't be used with thunks for thunk testing as those actually use the glibc allocator.
CI will run FEX's test suite with extra verification to ensure FEX makes no allocations are made through glibc. Thunking must be disabled for this
run, since thunks are by design the only place where glibc allocation still happen.