Fixes and workarounds to make UBSan happier on macOS
There are still some other issues not addressed here, but it's a start. Workarounds for false-positive reports: - `RasterizerAccelerated`: Put a gigantic array behind a `unique_ptr`, because UBSan has a [hardcoded limit](https://stackoverflow.com/questions/64531383/c-runtime-error-using-fsanitize-undefined-object-has-a-possibly-invalid-vp) of how big it thinks objects can be, specifically when dealing with offset-to-top values used with multiple inheritance. Hopefully this doesn't have a performance impact. - `QueryCacheBase::QueryCacheBase`: Avoid an operation that UBSan thinks is UB even though it at least arguably isn't. See the link in the comment for more information. Fixes for correct reports: - `PageTable`, `Memory`: Use `uintptr_t` values instead of pointers to avoid UB from pointer overflow (when pointer arithmetic wraps around the address space). - `KScheduler::Reload`: `thread->GetOwnerProcess()` can be `nullptr`; avoid calling methods on it in this case. (The existing code returns a garbage reference to a field, which is then passed into `LoadWatchpointArray`, and apparently it's never used, so it's harmless in practice but still triggers UBSan.) - `KAutoObject::Close`: This function calls `this->Destroy()`, which overwrites the beginning of the object with junk (specifically a free list pointer). Then it calls `this->UnregisterWithKernel()`. UBSan complains about a type mismatch because the vtable has been overwritten, and I believe this is indeed UB. `UnregisterWithKernel` also loads `m_kernel` from the 'freed' object, which seems to be technically safe (the overwriting doesn't extend as far as that field), but seems dubious. Switch to a `static` method and load `m_kernel` in advance.
This commit is contained in:
parent
04868ab9da
commit
d7c532d889
11 changed files with 42 additions and 32 deletions
|
@ -73,7 +73,7 @@ struct Memory::Impl {
|
|||
return {};
|
||||
}
|
||||
|
||||
return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
|
||||
return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
|
||||
}
|
||||
|
||||
[[nodiscard]] u8* GetPointerFromDebugMemory(u64 vaddr) const {
|
||||
|
@ -84,7 +84,7 @@ struct Memory::Impl {
|
|||
return {};
|
||||
}
|
||||
|
||||
return system.DeviceMemory().GetPointer<u8>(paddr) + vaddr;
|
||||
return system.DeviceMemory().GetPointer<u8>(paddr + vaddr);
|
||||
}
|
||||
|
||||
u8 Read8(const Common::ProcessAddress addr) {
|
||||
|
@ -204,7 +204,8 @@ struct Memory::Impl {
|
|||
break;
|
||||
}
|
||||
case Common::PageType::Memory: {
|
||||
u8* mem_ptr = pointer + page_offset + (page_index << YUZU_PAGEBITS);
|
||||
u8* mem_ptr =
|
||||
reinterpret_cast<u8*>(pointer + page_offset + (page_index << YUZU_PAGEBITS));
|
||||
on_memory(copy_amount, mem_ptr);
|
||||
break;
|
||||
}
|
||||
|
@ -448,7 +449,7 @@ struct Memory::Impl {
|
|||
break;
|
||||
case Common::PageType::Memory:
|
||||
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
|
||||
nullptr, Common::PageType::DebugMemory);
|
||||
0, Common::PageType::DebugMemory);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
@ -466,7 +467,8 @@ struct Memory::Impl {
|
|||
case Common::PageType::DebugMemory: {
|
||||
u8* const pointer{GetPointerFromDebugMemory(vaddr & ~YUZU_PAGEMASK)};
|
||||
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
|
||||
pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
|
||||
reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK),
|
||||
Common::PageType::Memory);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -506,7 +508,7 @@ struct Memory::Impl {
|
|||
case Common::PageType::DebugMemory:
|
||||
case Common::PageType::Memory:
|
||||
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
|
||||
nullptr, Common::PageType::RasterizerCachedMemory);
|
||||
0, Common::PageType::RasterizerCachedMemory);
|
||||
break;
|
||||
case Common::PageType::RasterizerCachedMemory:
|
||||
// There can be more than one GPU region mapped per CPU region, so it's common
|
||||
|
@ -534,10 +536,11 @@ struct Memory::Impl {
|
|||
// pagetable after unmapping a VMA. In that case the underlying VMA will no
|
||||
// longer exist, and we should just leave the pagetable entry blank.
|
||||
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
|
||||
nullptr, Common::PageType::Unmapped);
|
||||
0, Common::PageType::Unmapped);
|
||||
} else {
|
||||
current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Store(
|
||||
pointer - (vaddr & ~YUZU_PAGEMASK), Common::PageType::Memory);
|
||||
reinterpret_cast<uintptr_t>(pointer) - (vaddr & ~YUZU_PAGEMASK),
|
||||
Common::PageType::Memory);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -584,7 +587,7 @@ struct Memory::Impl {
|
|||
"Mapping memory page without a pointer @ {:016x}", base * YUZU_PAGESIZE);
|
||||
|
||||
while (base != end) {
|
||||
page_table.pointers[base].Store(nullptr, type);
|
||||
page_table.pointers[base].Store(0, type);
|
||||
page_table.backing_addr[base] = 0;
|
||||
page_table.blocks[base] = 0;
|
||||
base += 1;
|
||||
|
@ -593,7 +596,8 @@ struct Memory::Impl {
|
|||
auto orig_base = base;
|
||||
while (base != end) {
|
||||
auto host_ptr =
|
||||
system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS);
|
||||
reinterpret_cast<uintptr_t>(system.DeviceMemory().GetPointer<u8>(target)) -
|
||||
(base << YUZU_PAGEBITS);
|
||||
auto backing = GetInteger(target) - (base << YUZU_PAGEBITS);
|
||||
page_table.pointers[base].Store(host_ptr, type);
|
||||
page_table.backing_addr[base] = backing;
|
||||
|
@ -619,8 +623,8 @@ struct Memory::Impl {
|
|||
|
||||
// Avoid adding any extra logic to this fast-path block
|
||||
const uintptr_t raw_pointer = current_page_table->pointers[vaddr >> YUZU_PAGEBITS].Raw();
|
||||
if (u8* const pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
|
||||
return &pointer[vaddr];
|
||||
if (const uintptr_t pointer = Common::PageTable::PageInfo::ExtractPointer(raw_pointer)) {
|
||||
return reinterpret_cast<u8*>(pointer + vaddr);
|
||||
}
|
||||
switch (Common::PageTable::PageInfo::ExtractType(raw_pointer)) {
|
||||
case Common::PageType::Unmapped:
|
||||
|
@ -814,7 +818,7 @@ bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
|
|||
return false;
|
||||
}
|
||||
const auto [pointer, type] = page_table.pointers[page].PointerType();
|
||||
return pointer != nullptr || type == Common::PageType::RasterizerCachedMemory ||
|
||||
return pointer != 0 || type == Common::PageType::RasterizerCachedMemory ||
|
||||
type == Common::PageType::DebugMemory;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue