From 8a7365c0b3deb705c9c5747c670d101274b3935c Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Tue, 19 Aug 2025 10:15:02 +0200 Subject: [PATCH 1/2] Revert "Use g_fputs in g_printf, g_fprintf" This reverts commit 02c63162a46e03a3fb22fb43cf52a5c9be5ad0b2 and sets the glib/print test as can_fail on Windows. Fixes #3761 --- glib/gprintf.c | 14 ++------------ glib/tests/meson.build | 4 +++- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/glib/gprintf.c b/glib/gprintf.c index 495311058..3e775adc3 100644 --- a/glib/gprintf.c +++ b/glib/gprintf.c @@ -198,7 +198,7 @@ g_vprintf (gchar const *format, { g_return_val_if_fail (format != NULL, -1); - return g_vfprintf (stdout, format, args); + return _g_vprintf (format, args); } /** @@ -222,19 +222,9 @@ g_vfprintf (FILE *file, gchar const *format, va_list args) { - char *result = NULL; - int rlength; - g_return_val_if_fail (format != NULL, -1); - rlength = g_vasprintf (&result, format, args); - if (rlength < 0) - return rlength; - - rlength = g_fputs (result, file); - g_free (result); - - return rlength; + return _g_vfprintf (file, format, args); } /** diff --git a/glib/tests/meson.build b/glib/tests/meson.build index c4ceff9c5..76b031106 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -98,7 +98,9 @@ glib_tests = { }, 'pathbuf' : {}, 'pattern' : {}, - 'print' : {}, + 'print' : { + 'can_fail' : host_system == 'windows', + }, 'private' : {}, 'protocol' : {}, 'queue' : {}, From bb96c606ae52605351414c7c495db2e4bfecca60 Mon Sep 17 00:00:00 2001 From: Luca Bacci Date: Tue, 19 Aug 2025 17:05:03 +0200 Subject: [PATCH 2/2] tests/printf: Produce strings with embedded null characters See #3761 --- glib/tests/test-printf.c | 110 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/glib/tests/test-printf.c b/glib/tests/test-printf.c index 432685e3f..8caccd369 100644 --- a/glib/tests/test-printf.c +++ b/glib/tests/test-printf.c @@ -26,6 +26,9 @@ #include #include "glib.h" #include "gstdio.h" +#ifdef G_OS_UNIX +#include +#endif #ifdef G_OS_WIN32 #include #include @@ -876,6 +879,110 @@ test_64bit2 (void) #endif } +static void +test_produce_embedded_nulls (void) +{ + char buf[4]; + int length; + unsigned int i = 0; + + length = g_snprintf (buf, sizeof (buf), "%s%c%s", "a", '\0', "b"); + g_assert_cmpint (length, ==, 3); + g_assert_cmpint (buf[i++], ==, 'a'); + g_assert_cmpint (buf[i++], ==, '\0'); + g_assert_cmpint (buf[i++], ==, 'b'); + g_assert_cmpint (buf[i++], ==, '\0'); +} + +typedef struct +{ + FILE *stream; + size_t written; +} TestProduceEmbeddedNulls2ThreadData; + +static gpointer +test_produce_embedded_nulls2_writing_thread (gpointer user_data) +{ + TestProduceEmbeddedNulls2ThreadData *data; + + data = (TestProduceEmbeddedNulls2ThreadData *) user_data; + data->written = g_fprintf (data->stream, "%s%c%s", "a", '\0', "b"); + + g_assert_false (ferror (data->stream)); + g_assert_no_errno (fclose (data->stream)); + + return NULL; +} + +static void +test_produce_embedded_nulls2 (void) +{ + int fds[2] = { -1, -1 }; + + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3761"); + g_test_summary ("printf() functions can produce strings with embedded null " + "characters. That happens when passing individual characters " + "(%c) with value '\0'. Test that printing such strings via " + "g_fprintf() works as expected."); + +#ifdef G_OS_UNIX + GError *error = NULL; + g_unix_open_pipe (fds, O_CLOEXEC, &error); + g_assert_no_error (error); +#else + g_assert_no_errno (_pipe (fds, 0, _O_BINARY | _O_NOINHERIT)); +#endif + +#ifdef G_OS_UNIX +#define MODE_EXTRA "" +#else +#define MODE_EXTRA "b" +#endif + + FILE *streams[2] = { NULL, NULL }; + streams[0] = fdopen (fds[0], "r" MODE_EXTRA); + streams[1] = fdopen (fds[1], "w" MODE_EXTRA); + g_assert_nonnull (streams[0]); + g_assert_nonnull (streams[1]); + + TestProduceEmbeddedNulls2ThreadData data = { streams[1], 3 }; + + /* Do the writing on a separate thread to avoid any + * possibility of deadlocks */ + GThread *writing_thread = g_thread_new ("pipe writing thread", + test_produce_embedded_nulls2_writing_thread, + &data); + + char buf[3]; + char *iter = buf; + size_t size = sizeof (buf); + size_t read_bytes; + do + { + read_bytes = fread (iter, 1, size, streams[0]); + g_assert_cmpint (read_bytes, >, 0); + g_assert_cmpint (read_bytes, <=, size); + iter += read_bytes; + size -= read_bytes; + } + while (size > 0); + + char dummy; + read_bytes = fread (&dummy, 1, 1, streams[0]); + g_assert_cmpint (read_bytes, ==, 0); + + g_assert_false (ferror (streams[0])); + + g_thread_join (g_steal_pointer (&writing_thread)); + + g_assert_cmpint (data.written, ==, 3); + g_assert_cmpint (buf[0], ==, 'a'); + g_assert_cmpint (buf[1], ==, '\0'); + g_assert_cmpint (buf[2], ==, 'b'); + + g_assert_no_errno (fclose (streams[0])); +} + G_GNUC_PRINTF(1, 2) static gsize upper_bound (const gchar *format, ...) @@ -1000,6 +1107,7 @@ main (int argc, g_test_add_func ("/snprintf/test-percent", test_percent); g_test_add_func ("/snprintf/test-positional-params", test_positional_params); g_test_add_func ("/snprintf/test-64bit", test_64bit); + g_test_add_func ("/snprintf/produce-embedded-nulls", test_produce_embedded_nulls); g_test_add_func ("/printf/test-percent", test_percent2); g_test_add_func ("/printf/test-positional-params", test_positional_params2); @@ -1009,6 +1117,8 @@ main (int argc, g_test_add_func ("/printf/test-64bit/subprocess/win32", test_64bit2_win32); #endif + g_test_add_func ("/fprintf/produce-embedded-nulls", test_produce_embedded_nulls2); + g_test_add_func ("/sprintf/test-positional-params", test_positional_params3); g_test_add_func ("/sprintf/upper-bound", test_upper_bound);