Skip to content

Fix issues found by UBSan and ASan#1842

Open
fabioarnold wants to merge 8 commits intocemu-project:mainfrom
fabioarnold:fabio/fix-ub-issues
Open

Fix issues found by UBSan and ASan#1842
fabioarnold wants to merge 8 commits intocemu-project:mainfrom
fabioarnold:fabio/fix-ub-issues

Conversation

@fabioarnold
Copy link
Copy Markdown

These are various issues I encountered while starting up Zelda TPHD in a debug build of Cemu with UBSan and ASan enabled. Each commit fixes one issue.

Most of these are over-/underflows with signed integer arithmetic which is undefined behavior in C++. I fixed this using unsigned ints where over-/underflows are defined as wrapping.

{
return _swapEndianU32(*(uint32*)(memory_base + address));
uint32 v;
memcpy(&v, memory_base + address, sizeof(uint32));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah unfortunately we can't actually do this. In debug builds this will compile down to a function call plus some overhead and since the memory_* and ppcMem_* functions are all critical for performance (literally called many millions of times per frame) it would hurt performance too much. I further suspect that in release mode it will also not nicely compile down to a single instruction (which the old code does) since the compiler doesn't know that address is guaranteed to be aligned. So it will have to emit a byte-wise copy.

We can probably tell the compiler that the pointer is aligned via some assume construct but I wouldn't trust them to always optimize down to a dword fetch (it certainly wont optimize in debug builds).

C++23 has a solution for this: std::start_lifetime_as. So I think best course of action is to just wait until thats broadly available.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I observed an unaligned access by the game here. Can't really control or avoid that, right?

I haven't looked at the optimized assembly or measured performance. Would be worth it to check.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PowerPC has strict alignment requirements so that seems unlikely. Can you paste the call stack?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would crash on actual console so there must be a bug somewhere else causing the invalid address. What game is it and when does it trigger?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Twilight Princess HD. Just loading the game.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got rid of the commit that contained memcpy. I can still reliably trigger the unaligned read. This must be the result of another bug.

@fabioarnold fabioarnold force-pushed the fabio/fix-ub-issues branch from bd13048 to 3b99ddd Compare March 21, 2026 10:42
prevent misaligned pointer use by aligning tightly packed structs to 4
wrapping of signed integers is undefined behavior
__builtin_clzl is the 64 bit version

For example for _Mask 32 it calculated 31 - 58 = -27
Cast to uint32 gives 4294967269
- bpp=32: blockOutput is texelBaseType* (uint32_t, 4-byte aligned).
  Casting to uint64* and dereferencing is UB when the address is not
  8-byte aligned (e.g. 0x...c is 4-byte aligned but not 8-byte).
- bpp=8: blockOutput is texelBaseType* (uint8_t, 1-byte aligned).
  Casting to uint64* is UB for any address not divisible by 8.
@fabioarnold fabioarnold force-pushed the fabio/fix-ub-issues branch from 6160b95 to f26e716 Compare March 29, 2026 15:24
@fabioarnold
Copy link
Copy Markdown
Author

Apart from unaligned reads and writes in PPCInterpreterImpl.cpp with these changes I can load and run TPHD without trapping due to UBSand/ASan now.

@fabioarnold fabioarnold marked this pull request as ready for review March 29, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants