New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HLE_OS: Manually handle printfs from emulated software to prevent emulated software from crashing Dolphin with an invalid printf formatting string. #11025
Conversation
|
Just wondering, can't |
|
I think that still results in platform inconsistency (consider eg. platforms where long is 64 bit vs platforms where long is 32 bit), but feel free to give it a shot! e: Also you have to filter out anything the hooked function wouldn't support, like positional arguments... |
95c63f2
to
3fdbf30
Compare
3fdbf30
to
252cb99
Compare
b66be44
to
02acd40
Compare
63fcdbc
to
c955668
Compare
c955668
to
202323c
Compare
| do | ||
| { | ||
| if (!HostIsRAMAddress(guard, address) || !HostIsRAMAddress(guard, address + 1)) | ||
| break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this return error instead of "partial" string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly... but if yes so should HostGetString().
202323c
to
aa8c7d2
Compare
aa8c7d2
to
0b174f2
Compare
0b174f2
to
04b8d51
Compare
|
This has been sitting here long enough. I think it works, even if it's a bit ugly in spots, and it's definitely better than letting emulated software crash or worse write to arbitrary memory with a rogue printf statement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll review the rest of the PR, asap. I'm going to test it with a bunch of games I have which are displaying debug messages.
Source/Core/Core/PowerPC/MMU.cpp
Outdated
| u16 res = HostRead_U16(guard, address); | ||
| if (!res) | ||
| break; | ||
| s += static_cast<u16>(res); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't res be const'd and is the static_cast necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, that's supposed to cast to char16_t.
Source/Core/Core/HLE/HLE_OS.cpp
Outdated
| HLEPrintArgsVAList(const Core::CPUThreadGuard& guard, HLE::SystemVABI::VAList& va_list) | ||
| : m_guard(guard), m_va_list(va_list) | ||
| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't HLE::SystemVABI::VAList& va_list be passed as a pointer in case it's modified according to Dolphin's coding style? If the coding style has changed or allows some exceptions, they might be worth mentioning in the Contributing.md file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhm, I think that's actually ambiguous, since we're not actually assigning a new value to the passed va_list, but yeah sure it doesn't hurt.
326f81a
to
86f9846
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some more remarks.
I'm wondering, can't the remaining StringFromFormat be replaced with fmt::sprintf?
Source/Core/Core/HLE/HLE_OS.cpp
Outdated
| if (i >= string.size()) | ||
| { | ||
| // not a valid formatting string, print the formatting string as-is | ||
| result += string.substr(formatting_start_position); | ||
| break; | ||
|
|
||
| ArgumentBuffer += string[i]; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't you returning a partially formatted string instead of the original format string string? You're also skipping all the subsequent conversion specifications. I'm unsure of the behaviour on actual hardware/game/homebrew. I'll write some tests to see how they behave.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well this is undefined behavior, it's reading past the end of the string. This is basically if you had something like eg. printf("text %s %0", "something", 5);; that last %0 has a padding_zeroes_flag but then nothing else after it. I'd argue printing text something %0 in this case is more useful than printing text %s %0 but ymmv, we can technically do whatever.
9e66d5f
to
5bfc360
Compare
|
I've also changed the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise, this PR seems to work fine with the game I tested.
Source/Core/Core/HLE/HLE_OS.cpp
Outdated
| { | ||
| fmt::format_to(std::back_inserter(result), | ||
| fmt::runtime(left_justified_flag ? "{0:<{1}}" : "{0:>{1}}"), | ||
| static_cast<unsigned char>(value), field_width.value_or(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After some testing, I had a regression. Casting the value as signed or unsigned char will display it as an integer. This should be casted as plain char instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah so just static_cast<char>(value)? Weird that that makes a difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was surprised too, apparently it was done to fix uint8_t and int8_t being displayed as character instead of integer.
…lated software from crashing Dolphin with an invalid printf formatting string.
5bfc360
to
9f81791
Compare
|
@sepalani Any further comments? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. This PR is also better than the current way we're logging things. @dreamsyntax might want to double check that it still fixes the crashes on Shadow the Hedgehog.
Sadly, I'm unable to reproduce the crash mentioned by @dreamsyntax on Shadow the Hedgehog (PAL), with either this PR or master. Both tried to print nonsense still. There is no known symbol maps for this game, AFAIK, so Dolphin autodetection creates false positives.
I noticed one nlPrintf function at 8001c574 which doesn't seem log related but might use varargs. I was unable to figure out if its parameters point to valid strings.
Whereas, there is another function detected as ___blank at 8000d374 which might or might not be log related. However, it might be related to the boost library (v1.32, since the string occurrences don't exist prior to this version) and shared_ptr serialization. The first argument (r3) passed to this function when dereferenced several times points to r6 then a boost string. The r6 and r3 values are set right before the ___blank function call so there is a very high chance for them to be related.
Some examples (no surprise that dolphin autodection failed to find the string):
- r3=8060c534 -> 807f07a0 -> r6=80560298 -> 805ee9a0 (char**) -> 80512824 (char*)
- string at 80512824:
boost::detail::sp_counted_base_impl<Vibration::ManagerUnit *, boost::checked_deleter<Vibration::ManagerUnit>>
- string at 80512824:
- r3=8060c4f4 -> 807f0818 -> r6=8054ddac -> 805eba3c (char**) -> 804f7a10 (char*)
- string at 804f7a10:
boost::detail::sp_counted_base_impl<SonicteamUSA::System::Camera::CameraScreen *, boost::checked_deleter<SonicteamUSA::System::Camera::CameraScreen>>
- string at 804f7a10:

This is incomplete and not tested, I just was reminded that I had this. I may or may not come back to this, someone else is free to take this over if they want...
For reference, I'm unsure of the exact circumstances, but I have seen Dolphin crash from a game invoking a HLE-hooked
printf(), which is what triggered me going down this path.