memory: Improve null pointer and unmapped memory handling

- Update vcpkg baseline to a42af01b72c28a8e1d7b48107b33e4f286a55ef6
- Add SPIRV-Tools and SPIRV-Headers as submodules
- Update Vulkan-related submodules to latest stable versions
- Improve memory access error handling:
  - Add specific handling for null pointer accesses in ARM32 emulation
  - Return 0 for null pointer reads instead of undefined behavior
  - Silently ignore writes to null pointers
  - Add more detailed error messages distinguishing between null pointer
    access and other unmapped memory errors
  - Treat addresses below 0x1000 as potential null pointer accesses

These changes should provide more graceful handling of null pointer
accesses and improve stability when running games that attempt invalid
memory operations.
This commit is contained in:
Zephyron 2025-01-18 15:19:45 +10:00
parent 07b949025f
commit b938893599
10 changed files with 36 additions and 5 deletions

View file

@ -95,6 +95,13 @@ public:
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
ReturnException(pc, PrefetchAbort);
return;
case Dynarmic::A32::Exception::AccessViolation:
if (pc == 0 || pc < 0x1000) {
LOG_CRITICAL(Core_ARM, "Null pointer dereference at {:#08x}", pc);
ReturnException(pc, DataAbort);
return;
}
[[fallthrough]];
default:
if (m_debugger_enabled) {
ReturnException(pc, InstructionBreakpoint);

View file

@ -737,12 +737,21 @@ struct Memory::Impl {
const u8* const ptr = GetPointerImpl(
GetInteger(vaddr),
[vaddr]() {
// Add special handling for null pointer reads
if (GetInteger(vaddr) == 0 || GetInteger(vaddr) < 0x1000) {
LOG_ERROR(HW_Memory, "Null pointer Read{} @ 0x{:016X}", sizeof(T) * 8,
GetInteger(vaddr));
return;
}
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:016X}", sizeof(T) * 8,
GetInteger(vaddr));
},
[&]() { HandleRasterizerDownload(GetInteger(vaddr), sizeof(T)); });
if (ptr) {
std::memcpy(&result, ptr, sizeof(T));
} else if (GetInteger(vaddr) == 0) {
// Return 0 for null pointer reads instead of random memory
result = 0;
}
return result;
}
@ -761,6 +770,12 @@ struct Memory::Impl {
u8* const ptr = GetPointerImpl(
GetInteger(vaddr),
[vaddr, data]() {
// Add special handling for null pointer writes
if (GetInteger(vaddr) == 0 || GetInteger(vaddr) < 0x1000) {
LOG_ERROR(HW_Memory, "Null pointer Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
GetInteger(vaddr), static_cast<u64>(data));
return;
}
LOG_ERROR(HW_Memory, "Unmapped Write{} @ 0x{:016X} = 0x{:016X}", sizeof(T) * 8,
GetInteger(vaddr), static_cast<u64>(data));
},
@ -768,6 +783,7 @@ struct Memory::Impl {
if (ptr) {
std::memcpy(ptr, &data, sizeof(T));
}
// Silently ignore writes to null pointer
}
template <typename T>