| 
									
										
										
										
											2022-04-23 04:59:50 -04:00
										 |  |  | // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
 | 
					
						
							|  |  |  | // SPDX-License-Identifier: GPL-2.0-or-later
 | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  | #include <atomic>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | #include "common/assert.h"
 | 
					
						
							|  |  |  | #include "common/common_types.h"
 | 
					
						
							| 
									
										
										
										
											2021-03-02 16:57:53 -08:00
										 |  |  | #include "common/div_ceil.h"
 | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | #include "core/memory.h"
 | 
					
						
							|  |  |  | #include "video_core/rasterizer_accelerated.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace VideoCore { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  | using namespace Core::Memory; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												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.
											
										 
											2023-07-01 15:00:39 -07:00
										 |  |  | RasterizerAccelerated::RasterizerAccelerated(Memory& cpu_memory_) | 
					
						
							|  |  |  |     : cached_pages(std::make_unique<CachedPages>()), cpu_memory{cpu_memory_} {} | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | RasterizerAccelerated::~RasterizerAccelerated() = default; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) { | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |     u64 uncache_begin = 0; | 
					
						
							|  |  |  |     u64 cache_begin = 0; | 
					
						
							|  |  |  |     u64 uncache_bytes = 0; | 
					
						
							|  |  |  |     u64 cache_bytes = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::atomic_thread_fence(std::memory_order_acquire); | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |     const u64 page_end = Common::DivCeil(addr + size, YUZU_PAGESIZE); | 
					
						
							|  |  |  |     for (u64 page = addr >> YUZU_PAGEBITS; page != page_end; ++page) { | 
					
						
							| 
									
										
											  
											
												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.
											
										 
											2023-07-01 15:00:39 -07:00
										 |  |  |         std::atomic_uint16_t& count = cached_pages->at(page >> 2).Count(page); | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 17:48:02 -08:00
										 |  |  |         if (delta > 0) { | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |             ASSERT_MSG(count.load(std::memory_order::relaxed) < UINT16_MAX, "Count may overflow!"); | 
					
						
							| 
									
										
										
										
											2021-03-02 17:48:02 -08:00
										 |  |  |         } else if (delta < 0) { | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |             ASSERT_MSG(count.load(std::memory_order::relaxed) > 0, "Count may underflow!"); | 
					
						
							| 
									
										
										
										
											2021-03-02 17:44:02 -08:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |             ASSERT_MSG(false, "Delta must be non-zero!"); | 
					
						
							| 
									
										
										
										
											2021-03-02 17:44:02 -08:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-12 21:52:49 -08:00
										 |  |  |         // Adds or subtracts 1, as count is a unsigned 8-bit value
 | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |         count.fetch_add(static_cast<u16>(delta), std::memory_order_release); | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-02 16:57:53 -08:00
										 |  |  |         // Assume delta is either -1 or 1
 | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |         if (count.load(std::memory_order::relaxed) == 0) { | 
					
						
							|  |  |  |             if (uncache_bytes == 0) { | 
					
						
							|  |  |  |                 uncache_begin = page; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |             uncache_bytes += YUZU_PAGESIZE; | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |         } else if (uncache_bytes > 0) { | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |             cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, | 
					
						
							|  |  |  |                                                   false); | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |             uncache_bytes = 0; | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |         if (count.load(std::memory_order::relaxed) == 1 && delta > 0) { | 
					
						
							|  |  |  |             if (cache_bytes == 0) { | 
					
						
							|  |  |  |                 cache_begin = page; | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |             cache_bytes += YUZU_PAGESIZE; | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |         } else if (cache_bytes > 0) { | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |             cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |             cache_bytes = 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (uncache_bytes > 0) { | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |         cpu_memory.RasterizerMarkRegionCached(uncache_begin << YUZU_PAGEBITS, uncache_bytes, false); | 
					
						
							| 
									
										
										
										
											2021-06-06 20:58:57 -03:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (cache_bytes > 0) { | 
					
						
							| 
									
										
										
										
											2022-08-18 16:28:55 -07:00
										 |  |  |         cpu_memory.RasterizerMarkRegionCached(cache_begin << YUZU_PAGEBITS, cache_bytes, true); | 
					
						
							| 
									
										
										
										
											2019-10-27 03:40:08 -03:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // namespace VideoCore
 |