diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index 0141ece16..22ec7a1ee 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -581,7 +581,8 @@ g_strconcat (const gchar *string1, ...) s = va_arg (args, gchar*); while (s) { - l += strlen (s); + if (!g_size_checked_add (&l, l, strlen (s))) + g_error ("%s: overflow concatenating strings", G_STRLOC); s = va_arg (args, gchar*); } va_end (args); @@ -2645,13 +2646,18 @@ g_strjoinv (const gchar *separator, gsize i; gsize len; gsize separator_len; + gsize separators_len; separator_len = strlen (separator); /* First part, getting length */ len = 1 + strlen (str_array[0]); for (i = 1; str_array[i] != NULL; i++) - len += strlen (str_array[i]); - len += separator_len * (i - 1); + if (!g_size_checked_add (&len, len, strlen (str_array[i]))) + g_error ("%s: overflow joining strings", G_STRLOC); + + if (!g_size_checked_mul (&separators_len, separator_len, (i - 1)) || + !g_size_checked_add (&len, len, separators_len)) + g_error ("%s: overflow joining strings", G_STRLOC); /* Second part, building string */ string = g_new (gchar, len); @@ -2706,7 +2712,9 @@ g_strjoin (const gchar *separator, s = va_arg (args, gchar*); while (s) { - len += separator_len + strlen (s); + if (!g_size_checked_add (&len, len, separator_len) || + !g_size_checked_add (&len, len, strlen (s))) + g_error ("%s: overflow joining strings", G_STRLOC); s = va_arg (args, gchar*); } va_end (args); diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c index 3a6f745f2..278fbaed7 100644 --- a/glib/tests/strfuncs.c +++ b/glib/tests/strfuncs.c @@ -660,6 +660,46 @@ test_strconcat (void) g_assert_null (g_strconcat (NULL, "bla", NULL)); } +/* Testing g_strjoinv() function with strings which cannot be joined in heap */ +static void +test_strjoinv_overflow (void) +{ +#if G_MAXSIZE > G_MAXUINT + g_test_skip ("Overflow joining strings requires G_MAXSIZE <= G_MAXUINT."); +#else + if (!g_test_undefined ()) + return; + + if (g_test_subprocess ()) + { + /* compromise between memory consumption and performance */ + const size_t count = 256; + gchar **array; + gchar *result; + gchar *string; + + string = g_strnfill (G_MAXSIZE / ((count - 1) * 2), 'A'); + array = g_malloc_n (count + 1, sizeof (*array)); + + for (size_t i = 0; i < count; i++) + array[i] = string; + array[count] = NULL; + + result = g_strjoinv (string, array); + + g_free (array); + g_free (result); + g_free (string); + } + else + { + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_failed (); + g_test_trap_assert_stderr ("*overflow joining strings*"); + } +#endif +} + /* Testing g_strjoinv() function with various positive and negative cases */ static void test_strjoinv (void) @@ -2797,6 +2837,7 @@ main (int argc, g_test_add_func ("/strfuncs/strip-context", test_strip_context); g_test_add_func ("/strfuncs/strjoin", test_strjoin); g_test_add_func ("/strfuncs/strjoinv", test_strjoinv); + g_test_add_func ("/strfuncs/strjoinv/overflow", test_strjoinv_overflow); g_test_add_func ("/strfuncs/strlcat", test_strlcat); g_test_add_func ("/strfuncs/strlcpy", test_strlcpy); g_test_add_func ("/strfuncs/strncasecmp", test_strncasecmp);