[Kernel] Fix wide-printf functions not processing %ws format correctly

This would break format strings like memory://%.*ws (that dashboard tries using), because the "ws" part would set FF_IsWide, but FF_IsWide actually seemed to be used as an "is opposite encoding" flag.
Since the format string is wide that'd make it treat the param as ASCII, but in dashboards case the param string provided is actually a wide string.
(in other words, it seems %ws is supposed to mean that the param is always a wide string, not that the param is just opposite encoding)

This changes the old FF_IsWide to FF_InvertWide, and adds a new FF_IsWide that means that the param is always wide.
This commit is contained in:
emoose 2020-02-24 20:48:51 +00:00 committed by Rick Gibbed
parent ac5d548e90
commit 9185cdcc79
1 changed files with 7 additions and 10 deletions

View File

@ -49,6 +49,7 @@ enum FormatFlags {
FF_IsWide = 1 << 9,
FF_IsSigned = 1 << 10,
FF_ForceLeadingZero = 1 << 11,
FF_InvertWide = 1 << 12,
};
enum ArgumentSize {
@ -316,16 +317,14 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args,
// wide character
switch (c) {
case 'C': {
if (!(flags & (FF_IsShort | FF_IsLong | FF_IsWide))) {
flags |= FF_IsWide;
}
flags |= FF_InvertWide;
// fall through
}
// character
case 'c': {
bool is_wide;
if (flags & FF_IsLong) {
if (flags & (FF_IsLong | FF_IsWide)) {
// "An lc, lC, wc or wC type specifier is synonymous with C in
// printf functions and with c in wprintf functions."
is_wide = true;
@ -334,7 +333,7 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args,
// functions and with C in wprintf functions."
is_wide = false;
} else {
is_wide = ((flags & FF_IsWide) != 0) ^ wide;
is_wide = ((flags & FF_InvertWide) != 0) ^ wide;
}
auto value = args.get32();
@ -521,9 +520,7 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args,
// wide string
case 'S': {
if (!(flags & (FF_IsShort | FF_IsLong | FF_IsWide))) {
flags |= FF_IsWide;
}
flags |= FF_InvertWide;
// fall through
}
@ -540,7 +537,7 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args,
} else {
void* str = SHIM_MEM_ADDR(pointer);
bool is_wide;
if (flags & FF_IsLong) {
if (flags & (FF_IsLong | FF_IsWide)) {
// "An ls, lS, ws or wS type specifier is synonymous with S in
// printf functions and with s in wprintf functions."
is_wide = true;
@ -549,7 +546,7 @@ int32_t format_core(PPCContext* ppc_context, FormatData& data, ArgList& args,
// functions and with S in wprintf functions."
is_wide = false;
} else {
is_wide = ((flags & (FF_IsWide)) != 0) ^ wide;
is_wide = ((flags & FF_InvertWide) != 0) ^ wide;
}
int32_t length;