mirror of https://github.com/OpenRCT2/OpenRCT2.git
Fix #4762: Assertion in localisation (format_string_part)
The buffer overflow protection in format_string was not working correctly for several reasons. For windows builds this just so happened to write over gMapTooltipFormatArgs causing the assertion. Extra asserts have been added to check overflows in format_string.
This commit is contained in:
parent
1f0b2aefb7
commit
953f479cd9
|
@ -510,6 +510,7 @@ static void format_append_string(char **dest, size_t *size, const utf8 *string)
|
||||||
if (length < (*size)) {
|
if (length < (*size)) {
|
||||||
memcpy((*dest), string, length);
|
memcpy((*dest), string, length);
|
||||||
(*dest) += length;
|
(*dest) += length;
|
||||||
|
(*size) -= length;
|
||||||
} else {
|
} else {
|
||||||
memcpy((*dest), string, (*size) - 1);
|
memcpy((*dest), string, (*size) - 1);
|
||||||
(*dest) += (*size) - 1;
|
(*dest) += (*size) - 1;
|
||||||
|
@ -524,6 +525,7 @@ static void format_append_string_n(char **dest, size_t *size, const utf8 *string
|
||||||
if (length < (*size)) {
|
if (length < (*size)) {
|
||||||
memcpy((*dest), string, length);
|
memcpy((*dest), string, length);
|
||||||
(*dest) += length;
|
(*dest) += length;
|
||||||
|
(*size) -= length;
|
||||||
} else {
|
} else {
|
||||||
memcpy((*dest), string, (*size) - 1);
|
memcpy((*dest), string, (*size) - 1);
|
||||||
(*dest) += (*size) - 1;
|
(*dest) += (*size) - 1;
|
||||||
|
@ -1237,17 +1239,22 @@ static void format_string_part_from_raw(utf8 **dest, size_t *size, const utf8 *s
|
||||||
} else if (code < FORMAT_COLOUR_CODE_START || code == FORMAT_COMMA1DP16) {
|
} else if (code < FORMAT_COLOUR_CODE_START || code == FORMAT_COMMA1DP16) {
|
||||||
format_string_code(code, dest, size, args);
|
format_string_code(code, dest, size, args);
|
||||||
} else {
|
} else {
|
||||||
format_handle_overflow((size_t) utf8_get_codepoint_length(code));
|
size_t codepointLength = (size_t)utf8_get_codepoint_length(code);
|
||||||
*dest = utf8_write_codepoint(*dest, code);
|
format_handle_overflow(codepointLength);
|
||||||
|
if (*size > codepointLength) {
|
||||||
|
*dest = utf8_write_codepoint(*dest, code);
|
||||||
|
*size -= codepointLength;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*(*dest) = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void format_string_part(utf8 **dest, size_t *size, rct_string_id format, char **args)
|
static void format_string_part(utf8 **dest, size_t *size, rct_string_id format, char **args)
|
||||||
{
|
{
|
||||||
if (format == STR_NONE) {
|
if (format == STR_NONE) {
|
||||||
*(*dest) = '\0';
|
if (*size > 0) {
|
||||||
|
*(*dest) = '\0';
|
||||||
|
}
|
||||||
} else if (format < 0x8000) {
|
} else if (format < 0x8000) {
|
||||||
// Language string
|
// Language string
|
||||||
const utf8 * rawString = language_get_string(format);
|
const utf8 * rawString = language_get_string(format);
|
||||||
|
@ -1296,11 +1303,26 @@ void format_string(utf8 *dest, size_t size, rct_string_id format, void *args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
utf8 *end = dest;
|
utf8 *end = dest;
|
||||||
size_t left = size;
|
size_t left = size;
|
||||||
format_string_part(&end, &left, format, (char**)&args);
|
format_string_part(&end, &left, format, (char**)&args);
|
||||||
if (left == 0)
|
if (left == 0) {
|
||||||
|
// Replace last character with null terminator
|
||||||
|
*(end - 1) = '\0';
|
||||||
log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size);
|
log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size);
|
||||||
|
} else {
|
||||||
|
// Null terminate
|
||||||
|
*end = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Check if characters were written past the end of the buffer
|
||||||
|
assert(end <= dest + size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_string_raw(utf8 *dest, size_t size, utf8 *src, void *args)
|
void format_string_raw(utf8 *dest, size_t size, utf8 *src, void *args)
|
||||||
|
@ -1311,11 +1333,26 @@ void format_string_raw(utf8 *dest, size_t size, utf8 *src, void *args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
utf8 *end = dest;
|
utf8 *end = dest;
|
||||||
size_t left = size;
|
size_t left = size;
|
||||||
format_string_part_from_raw(&end, &left, src, (char**)&args);
|
format_string_part_from_raw(&end, &left, src, (char**)&args);
|
||||||
if (left == 0)
|
if (left == 0) {
|
||||||
|
// Replace last character with null terminator
|
||||||
|
*(end - 1) = '\0';
|
||||||
log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size);
|
log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size);
|
||||||
|
} else {
|
||||||
|
// Null terminate
|
||||||
|
*end = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Check if characters were written past the end of the buffer
|
||||||
|
assert(end <= dest + size);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1327,14 +1364,21 @@ void format_string_raw(utf8 *dest, size_t size, utf8 *src, void *args)
|
||||||
*/
|
*/
|
||||||
void format_string_to_upper(utf8 *dest, size_t size, rct_string_id format, void *args)
|
void format_string_to_upper(utf8 *dest, size_t size, rct_string_id format, void *args)
|
||||||
{
|
{
|
||||||
utf8 *end = dest;
|
#ifdef DEBUG
|
||||||
size_t left = size;
|
if (gDebugStringFormatting) {
|
||||||
format_string_part(&end, &left, format, (char**)&args);
|
printf("format_string_to_upper(%hu)\n", format);
|
||||||
if (left == 0)
|
}
|
||||||
log_warning("Truncating formatted string \"%s\" to %d bytes.", dest, size);
|
#endif
|
||||||
|
|
||||||
char *ch = dest;
|
if (size == 0) {
|
||||||
while (ch < end) {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_string(dest, size, format, args);
|
||||||
|
|
||||||
|
// Convert to upper case
|
||||||
|
utf8 *ch = dest;
|
||||||
|
while (*ch != '\0') {
|
||||||
*ch = toupper(*ch);
|
*ch = toupper(*ch);
|
||||||
ch++;
|
ch++;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue