diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81e8fecc..4ad34679 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -202,6 +202,7 @@ jobs: run: | cmake --build _Build/macos \ --target launcher audio_out2_port_tests pad_haptics_tests ime_dialog_tests lru_cache_tests virtual_memory_allocation_tests \ + memory_tracker_tests page_manager_tests shader_recompiler_compute_tests \ resource_tracking_tests scalar_provenance_tests \ resource_materialization_tests shader_vertex_metadata_tests archive_file_tests avplayer_file_tests \ --parallel @@ -210,7 +211,7 @@ jobs: shell: bash run: | ctest --test-dir _Build/macos --output-on-failure \ - -R '^(audio_out2_port|pad_haptics|ime_dialog|lru_cache|resource_tracking|scalar_provenance|resource_materialization|shader_vertex_metadata|archive_file|avplayer_file|virtual_memory_allocation)$' + -R '^(audio_out2_port|pad_haptics|ime_dialog|lru_cache|memory_tracker|page_manager|resource_tracking|scalar_provenance|resource_materialization|shader_vertex_metadata|archive_file|avplayer_file|virtual_memory_allocation)$' - name: Install shell: bash diff --git a/tests/MemoryTrackerTests.cpp b/tests/MemoryTrackerTests.cpp index 67572717..dcd5ccfc 100644 --- a/tests/MemoryTrackerTests.cpp +++ b/tests/MemoryTrackerTests.cpp @@ -22,6 +22,16 @@ #include #undef min #undef max +#elif defined(__APPLE__) +#include +#include +#include +#include +#include +#include +#include +#include +#include #else #include #include @@ -66,6 +76,26 @@ int ToHostProt(uint32_t protection) { } uint32_t Protection(const void *address) { +#if defined(__APPLE__) + mach_vm_address_t region_address = + reinterpret_cast(address); + mach_vm_size_t region_size = 0; + vm_region_basic_info_data_64_t info{}; + mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name = MACH_PORT_NULL; + Check(mach_vm_region(mach_task_self(), ®ion_address, ®ion_size, + VM_REGION_BASIC_INFO_64, + reinterpret_cast(&info), &info_count, + &object_name) == KERN_SUCCESS, + "mach_vm_region failed"); + if (object_name != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), object_name); + } + return (info.protection & VM_PROT_WRITE) != 0 + ? PAGE_READWRITE + : (info.protection & VM_PROT_READ) != 0 ? PAGE_READONLY + : PAGE_NOACCESS; +#else const auto addr = reinterpret_cast(address); std::FILE *maps = std::fopen("/proc/self/maps", "r"); Check(maps != nullptr, "open /proc/self/maps failed"); @@ -87,6 +117,7 @@ uint32_t Protection(const void *address) { } std::fclose(maps); return result; +#endif } std::map &AllocationSizes() { @@ -95,6 +126,23 @@ std::map &AllocationSizes() { } void *VirtualAlloc(void *address, size_t size, DWORD, uint32_t protection) { +#if defined(__APPLE__) + mach_vm_address_t raw_address = reinterpret_cast(address); + const auto flags = address != nullptr ? VM_FLAGS_FIXED : VM_FLAGS_ANYWHERE; + if (mach_vm_allocate(mach_task_self(), &raw_address, size, flags) != + KERN_SUCCESS) { + return nullptr; + } + if (mach_vm_protect(mach_task_self(), raw_address, size, false, + static_cast(ToHostProt(protection))) != + KERN_SUCCESS) { + mach_vm_deallocate(mach_task_self(), raw_address, size); + return nullptr; + } + void *raw = reinterpret_cast(raw_address); + AllocationSizes()[raw] = size; + return raw; +#else const int extra = address != nullptr ? MAP_FIXED_NOREPLACE : 0; void *raw = ::mmap(address, size, ToHostProt(protection), MAP_PRIVATE | MAP_ANONYMOUS | extra, -1, 0); @@ -103,6 +151,7 @@ void *VirtualAlloc(void *address, size_t size, DWORD, uint32_t protection) { } AllocationSizes()[raw] = size; return raw; +#endif } int VirtualFree(void *address, size_t, DWORD) { @@ -111,7 +160,15 @@ int VirtualFree(void *address, size_t, DWORD) { if (it == sizes.end()) { return 0; } +#if defined(__APPLE__) + const int ok = mach_vm_deallocate(mach_task_self(), + reinterpret_cast(address), + it->second) == KERN_SUCCESS + ? 1 + : 0; +#else const int ok = ::munmap(address, it->second) == 0 ? 1 : 0; +#endif sizes.erase(it); return ok; } @@ -121,7 +178,16 @@ int VirtualProtect(void *address, size_t size, uint32_t protection, if (old_protection != nullptr) { *old_protection = Protection(address); } +#if defined(__APPLE__) + return mach_vm_protect(mach_task_self(), + reinterpret_cast(address), size, + false, static_cast(ToHostProt(protection))) == + KERN_SUCCESS + ? 1 + : 0; +#else return ::mprotect(address, size, ToHostProt(protection)) == 0 ? 1 : 0; +#endif } #else uint32_t Protection(const void *address) { @@ -833,10 +899,23 @@ void CheckDeathCase(const char *name) { CloseHandle(process.hThread); CloseHandle(process.hProcess); #else +#if defined(__APPLE__) + std::vector path(PATH_MAX); + uint32_t path_size = static_cast(path.size()); + if (_NSGetExecutablePath(path.data(), &path_size) != 0) { + path.resize(path_size); + Check(_NSGetExecutablePath(path.data(), &path_size) == 0, + "_NSGetExecutablePath failed"); + } +#endif const pid_t pid = ::fork(); Check(pid >= 0, "fork failed"); if (pid == 0) { +#if defined(__APPLE__) + ::execl(path.data(), "MemoryTrackerTests", "--death", name, nullptr); +#else ::execl("/proc/self/exe", "MemoryTrackerTests", "--death", name, nullptr); +#endif std::_Exit(0x7e); } int status = 0; diff --git a/tests/PageManagerTests.cpp b/tests/PageManagerTests.cpp index 85aa3bcc..d1a5e631 100644 --- a/tests/PageManagerTests.cpp +++ b/tests/PageManagerTests.cpp @@ -16,6 +16,15 @@ #include #undef min #undef max +#elif defined(__APPLE__) +#include +#include +#include +#include +#include +#include +#include +#include #else #include #include @@ -56,6 +65,26 @@ int ToHostProt(uint32_t protection) { } uint32_t Protection(const void *address) { +#if defined(__APPLE__) + mach_vm_address_t region_address = + reinterpret_cast(address); + mach_vm_size_t region_size = 0; + vm_region_basic_info_data_64_t info{}; + mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name = MACH_PORT_NULL; + Check(mach_vm_region(mach_task_self(), ®ion_address, ®ion_size, + VM_REGION_BASIC_INFO_64, + reinterpret_cast(&info), &info_count, + &object_name) == KERN_SUCCESS, + "mach_vm_region failed"); + if (object_name != MACH_PORT_NULL) { + mach_port_deallocate(mach_task_self(), object_name); + } + return (info.protection & VM_PROT_WRITE) != 0 + ? PAGE_READWRITE + : (info.protection & VM_PROT_READ) != 0 ? PAGE_READONLY + : PAGE_NOACCESS; +#else const auto addr = reinterpret_cast(address); std::FILE *maps = std::fopen("/proc/self/maps", "r"); Check(maps != nullptr, "open /proc/self/maps failed"); @@ -77,6 +106,7 @@ uint32_t Protection(const void *address) { } std::fclose(maps); return result; +#endif } std::map &AllocationSizes() { @@ -90,7 +120,15 @@ int VirtualFree(void *address, size_t, DWORD) { if (it == sizes.end()) { return 0; } +#if defined(__APPLE__) + const int ok = mach_vm_deallocate(mach_task_self(), + reinterpret_cast(address), + it->second) == KERN_SUCCESS + ? 1 + : 0; +#else const int ok = ::munmap(address, it->second) == 0 ? 1 : 0; +#endif sizes.erase(it); return ok; } @@ -100,7 +138,16 @@ int VirtualProtect(void *address, size_t size, uint32_t protection, if (old_protection != nullptr) { *old_protection = Protection(address); } +#if defined(__APPLE__) + return mach_vm_protect(mach_task_self(), + reinterpret_cast(address), size, + false, static_cast(ToHostProt(protection))) == + KERN_SUCCESS + ? 1 + : 0; +#else return ::mprotect(address, size, ToHostProt(protection)) == 0 ? 1 : 0; +#endif } #else uint32_t Protection(const void *address) { @@ -144,6 +191,16 @@ uint8_t *Allocate(uint64_t size, uint32_t protection = PAGE_READWRITE, MEM_RESERVE | MEM_COMMIT, protection)); Check(memory == reinterpret_cast(test_address), "fixed low VirtualAlloc failed"); +#elif defined(__APPLE__) + mach_vm_address_t raw = test_address; + Check(mach_vm_allocate(mach_task_self(), &raw, size, VM_FLAGS_FIXED) == + KERN_SUCCESS && + mach_vm_protect(mach_task_self(), raw, size, false, + static_cast(ToHostProt(protection))) == + KERN_SUCCESS, + "fixed low mach_vm_allocate failed"); + auto *memory = reinterpret_cast(raw); + AllocationSizes()[memory] = static_cast(size); #else void *raw = ::mmap(reinterpret_cast(test_address), size, ToHostProt(protection), @@ -540,10 +597,23 @@ void CheckDeathCase(const char *name) { CloseHandle(process.hThread); CloseHandle(process.hProcess); #else +#if defined(__APPLE__) + std::vector path(PATH_MAX); + uint32_t path_size = static_cast(path.size()); + if (_NSGetExecutablePath(path.data(), &path_size) != 0) { + path.resize(path_size); + Check(_NSGetExecutablePath(path.data(), &path_size) == 0, + "_NSGetExecutablePath failed"); + } +#endif const pid_t pid = ::fork(); Check(pid >= 0, "fork failed"); if (pid == 0) { +#if defined(__APPLE__) + ::execl(path.data(), "PageManagerTests", "--death", name, nullptr); +#else ::execl("/proc/self/exe", "PageManagerTests", "--death", name, nullptr); +#endif std::_Exit(0x7e); } int status = 0; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index daecf5fc..e4a024df 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -9743,7 +9743,7 @@ public: std::memset(mapped, 0, allocation_size); for (uint32_t face = 0; face < layers; face++) { const auto depth = depth_at(face, false); - for (const auto address : {base, ordinary_address}) { + for (const auto address : {static_cast(base), ordinary_address}) { std::memcpy(reinterpret_cast(address + face * 0x100), &depth, sizeof(depth)); }