Fix macOS aggregate test build (#536)

* tests: add Darwin memory test support

* tests: fix x86_64 aggregate test build

* tests: verify macOS memory and shader tests

* tests: validate macOS death-test setup before fork

---------

Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
Saif Malik 2026-09-28 17:43:28 -04:00 committed by GitHub
parent 21d7e8e1f0
commit 6f241bef49
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 152 additions and 2 deletions

View File

@ -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

View File

@ -22,6 +22,16 @@
#include <windows.h>
#undef min
#undef max
#elif defined(__APPLE__)
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach-o/dyld.h>
#include <csignal>
#include <limits.h>
#include <map>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#else
#include <csignal>
#include <map>
@ -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<mach_vm_address_t>(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(), &region_address, &region_size,
VM_REGION_BASIC_INFO_64,
reinterpret_cast<vm_region_info_t>(&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<uintptr_t>(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<void *, size_t> &AllocationSizes() {
@ -95,6 +126,23 @@ std::map<void *, size_t> &AllocationSizes() {
}
void *VirtualAlloc(void *address, size_t size, DWORD, uint32_t protection) {
#if defined(__APPLE__)
mach_vm_address_t raw_address = reinterpret_cast<mach_vm_address_t>(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<vm_prot_t>(ToHostProt(protection))) !=
KERN_SUCCESS) {
mach_vm_deallocate(mach_task_self(), raw_address, size);
return nullptr;
}
void *raw = reinterpret_cast<void *>(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<mach_vm_address_t>(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<mach_vm_address_t>(address), size,
false, static_cast<vm_prot_t>(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<char> path(PATH_MAX);
uint32_t path_size = static_cast<uint32_t>(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;

View File

@ -16,6 +16,15 @@
#include <windows.h>
#undef min
#undef max
#elif defined(__APPLE__)
#include <limits.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach-o/dyld.h>
#include <map>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#else
#include <map>
#include <sys/mman.h>
@ -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<mach_vm_address_t>(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(), &region_address, &region_size,
VM_REGION_BASIC_INFO_64,
reinterpret_cast<vm_region_info_t>(&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<uintptr_t>(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<void *, size_t> &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<mach_vm_address_t>(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<mach_vm_address_t>(address), size,
false, static_cast<vm_prot_t>(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<void *>(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<vm_prot_t>(ToHostProt(protection))) ==
KERN_SUCCESS,
"fixed low mach_vm_allocate failed");
auto *memory = reinterpret_cast<uint8_t *>(raw);
AllocationSizes()[memory] = static_cast<size_t>(size);
#else
void *raw = ::mmap(reinterpret_cast<void *>(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<char> path(PATH_MAX);
uint32_t path_size = static_cast<uint32_t>(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;

View File

@ -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<uint64_t>(base), ordinary_address}) {
std::memcpy(reinterpret_cast<void *>(address + face * 0x100),
&depth, sizeof(depth));
}