diff options
| author | 2023-07-01 15:00:39 -0700 | |
|---|---|---|
| committer | 2023-07-15 12:00:28 -0700 | |
| commit | d7c532d8894ce806c9af13b8dd3eec975642b348 (patch) | |
| tree | 1353e6d1776384575019db28987e23237552a9de /src/common | |
| parent | file_sys/content_archive: Detect compressed NCAs (#11047) (diff) | |
| download | yuzu-d7c532d8894ce806c9af13b8dd3eec975642b348.tar.gz yuzu-d7c532d8894ce806c9af13b8dd3eec975642b348.tar.xz yuzu-d7c532d8894ce806c9af13b8dd3eec975642b348.zip | |
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.
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/page_table.h | 12 |
1 files changed, 6 insertions, 6 deletions
diff --git a/src/common/page_table.h b/src/common/page_table.h index fec8378f3..e653d52ad 100644 --- a/src/common/page_table.h +++ b/src/common/page_table.h | |||
| @@ -51,7 +51,7 @@ struct PageTable { | |||
| 51 | class PageInfo { | 51 | class PageInfo { |
| 52 | public: | 52 | public: |
| 53 | /// Returns the page pointer | 53 | /// Returns the page pointer |
| 54 | [[nodiscard]] u8* Pointer() const noexcept { | 54 | [[nodiscard]] uintptr_t Pointer() const noexcept { |
| 55 | return ExtractPointer(raw.load(std::memory_order_relaxed)); | 55 | return ExtractPointer(raw.load(std::memory_order_relaxed)); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| @@ -61,7 +61,7 @@ struct PageTable { | |||
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | /// Returns the page pointer and attribute pair, extracted from the same atomic read | 63 | /// Returns the page pointer and attribute pair, extracted from the same atomic read |
| 64 | [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept { | 64 | [[nodiscard]] std::pair<uintptr_t, PageType> PointerType() const noexcept { |
| 65 | const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); | 65 | const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed); |
| 66 | return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; | 66 | return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)}; |
| 67 | } | 67 | } |
| @@ -73,13 +73,13 @@ struct PageTable { | |||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | /// Write a page pointer and type pair atomically | 75 | /// Write a page pointer and type pair atomically |
| 76 | void Store(u8* pointer, PageType type) noexcept { | 76 | void Store(uintptr_t pointer, PageType type) noexcept { |
| 77 | raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type)); | 77 | raw.store(pointer | static_cast<uintptr_t>(type)); |
| 78 | } | 78 | } |
| 79 | 79 | ||
| 80 | /// Unpack a pointer from a page info raw representation | 80 | /// Unpack a pointer from a page info raw representation |
| 81 | [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept { | 81 | [[nodiscard]] static uintptr_t ExtractPointer(uintptr_t raw) noexcept { |
| 82 | return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS)); | 82 | return raw & (~uintptr_t{0} << ATTRIBUTE_BITS); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | /// Unpack a page type from a page info raw representation | 85 | /// Unpack a page type from a page info raw representation |