mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-05-19 20:12:10 +02:00
gprintf: Fix invalid size allocation in g_vasprintf()
As per the previous commit, it’s possible for `g_printf_string_upper_bound()` to return an error. We need to catch and handle that error in `g_vasprintf()` to avoid it trying to write to a `NULL` string allocation and crashing. So, call `g_vsnprintf()` directly instead of calling `g_printf_string_upper_bound()`, so that the error case can be handled. There was already a test for some of this behaviour (`test_vasprintf_invalid_format_placeholder()`). Because it tested an invalid format string, the `_g_vsprintf()` call bailed out before checking whether the buffer it had been passed was `NULL`. The new test has a valid format string, but an invalid arg. When running the tests locally, I have disabled the `USE_SYSTEM_PRINTF` and `HAVE_VASPRINTF` code paths in `g_vasprintf()`. Signed-off-by: Philip Withnall <pwithnall@gnome.org> Fixes: #3187
This commit is contained in:
parent
e2cd0962c2
commit
3c6052f318
@ -359,19 +359,29 @@ g_vasprintf (gchar **string,
|
|||||||
|
|
||||||
{
|
{
|
||||||
va_list args2;
|
va_list args2;
|
||||||
|
char c;
|
||||||
|
int max_len;
|
||||||
|
|
||||||
va_copy (args2, args);
|
va_copy (args2, args);
|
||||||
|
|
||||||
*string = g_new (gchar, g_printf_string_upper_bound (format, args));
|
max_len = _g_vsnprintf (&c, 1, format, args);
|
||||||
|
if (max_len < 0)
|
||||||
|
{
|
||||||
|
/* This can happen if @format contains `%ls` or `%lc` and @args contains
|
||||||
|
* something not representable in the current locale’s encoding (which
|
||||||
|
* should be UTF-8, but ymmv). Basically: don’t use `%ls` or `%lc`. */
|
||||||
|
va_end (args2);
|
||||||
|
*string = NULL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*string = g_new (gchar, (size_t) max_len + 1);
|
||||||
|
|
||||||
len = _g_vsprintf (*string, format, args2);
|
len = _g_vsprintf (*string, format, args2);
|
||||||
va_end (args2);
|
va_end (args2);
|
||||||
|
|
||||||
if (len < 0)
|
/* _g_vsprintf() should have exactly the same failure modes as _g_vsnprintf() */
|
||||||
{
|
g_assert (len >= 0);
|
||||||
g_free (*string);
|
|
||||||
*string = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -948,6 +948,30 @@ test_vasprintf_invalid_format_placeholder (void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_vasprintf_invalid_wide_string (void)
|
||||||
|
{
|
||||||
|
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||||
|
gint len = 0;
|
||||||
|
gchar *buf = "some non-null string";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
g_test_summary ("Test error handling for invalid wide strings in g_vasprintf()");
|
||||||
|
|
||||||
|
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wformat"
|
||||||
|
#pragma GCC diagnostic ignored "-Wformat-extra-args"
|
||||||
|
len = test_vasprintf_va (&buf, "%ls", L"\xD800" /* incomplete surrogate pair */);
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
|
g_assert_cmpint (len, ==, -1);
|
||||||
|
g_assert_null (buf);
|
||||||
|
#else
|
||||||
|
g_test_skip ("vasprintf() placeholder checks on BSDs are less strict");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc,
|
main (int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
@ -989,6 +1013,7 @@ main (int argc,
|
|||||||
g_test_add_func ("/sprintf/upper-bound", test_upper_bound);
|
g_test_add_func ("/sprintf/upper-bound", test_upper_bound);
|
||||||
|
|
||||||
g_test_add_func ("/vasprintf/invalid-format-placeholder", test_vasprintf_invalid_format_placeholder);
|
g_test_add_func ("/vasprintf/invalid-format-placeholder", test_vasprintf_invalid_format_placeholder);
|
||||||
|
g_test_add_func ("/vasprintf/invalid-wide-string", test_vasprintf_invalid_wide_string);
|
||||||
|
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user