diff options
Diffstat (limited to 'glib/gmessages.c')
-rw-r--r-- | glib/gmessages.c | 322 |
1 files changed, 166 insertions, 156 deletions
diff --git a/glib/gmessages.c b/glib/gmessages.c index 97c5b31b1..541b08130 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -192,6 +192,7 @@ #include "gcharset.h" #include "gconvert.h" #include "genviron.h" +#include "glib-private.h" #include "gmain.h" #include "gmem.h" #include "gprintfint.h" @@ -202,6 +203,10 @@ #include "gpattern.h" #include "gthreadprivate.h" +#if defined(__linux__) && !defined(__BIONIC__) +#include "gjournal-private.h" +#endif + #ifdef G_OS_UNIX #include <unistd.h> #endif @@ -215,22 +220,6 @@ #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 #endif -#if defined (_MSC_VER) && (_MSC_VER >=1400) -/* This is ugly, but we need it for isatty() in case we have bad fd's, - * otherwise Windows will abort() the program on msvcrt80.dll and later - */ -#include <crtdbg.h> - -_GLIB_EXTERN void -myInvalidParameterHandler(const wchar_t *expression, - const wchar_t *function, - const wchar_t *file, - unsigned int line, - uintptr_t pReserved) -{ -} -#endif - #include "gwin32.h" #endif @@ -512,12 +501,14 @@ struct _GLogHandler GLogHandler *next; }; +static void g_default_print_func (const gchar *string); +static void g_default_printerr_func (const gchar *string); /* --- variables --- */ static GMutex g_messages_lock; static GLogDomain *g_log_domains = NULL; -static GPrintFunc glib_print_func = NULL; -static GPrintFunc glib_printerr_func = NULL; +static GPrintFunc glib_print_func = g_default_print_func; +static GPrintFunc glib_printerr_func = g_default_printerr_func; static GPrivate g_log_depth; static GPrivate g_log_structured_depth; static GLogFunc default_log_func = g_log_default_handler; @@ -532,6 +523,11 @@ static gboolean g_log_debug_enabled = FALSE; /* (atomic) */ /* --- functions --- */ static void _g_log_abort (gboolean breakpoint); +static inline const char * format_string (const char *format, + va_list args, + char **out_allocated_string) + G_GNUC_PRINTF (1, 0); +static inline FILE * log_level_to_file (GLogLevelFlags log_level); static void _g_log_abort (gboolean breakpoint) @@ -597,7 +593,12 @@ static void write_string (FILE *stream, const gchar *string) { - fputs (string, stream); + if (fputs (string, stream) == EOF) + { + /* Something failed, but it's not an error we can handle at glib level + * so let's just continue without the compiler blaming us + */ + } } static void @@ -608,8 +609,12 @@ write_string_sized (FILE *stream, /* Is it nul-terminated? */ if (length < 0) write_string (stream, string); - else - fwrite (string, 1, length, stream); + else if (fwrite (string, 1, length, stream) < (size_t) length) + { + /* Something failed, but it's not an error we can handle at glib level + * so let's just continue without the compiler blaming us + */ + } } static GLogDomain* @@ -1204,8 +1209,6 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], GLogLevelFlags log_level, gboolean use_color) { - gboolean to_stdout = !gmessages_use_stderr; - /* we may not call _any_ GLib functions here */ strcpy (level_prefix, log_level_to_color (log_level, use_color)); @@ -1214,19 +1217,15 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], { case G_LOG_LEVEL_ERROR: strcat (level_prefix, "ERROR"); - to_stdout = FALSE; break; case G_LOG_LEVEL_CRITICAL: strcat (level_prefix, "CRITICAL"); - to_stdout = FALSE; break; case G_LOG_LEVEL_WARNING: strcat (level_prefix, "WARNING"); - to_stdout = FALSE; break; case G_LOG_LEVEL_MESSAGE: strcat (level_prefix, "Message"); - to_stdout = FALSE; break; case G_LOG_LEVEL_INFO: strcat (level_prefix, "INFO"); @@ -1256,7 +1255,7 @@ mklevel_prefix (gchar level_prefix[STRING_BUFFER_SIZE], if ((log_level & G_LOG_FLAG_FATAL) != 0 && !g_test_initialized ()) win32_keep_fatal_message = TRUE; #endif - return to_stdout ? stdout : stderr; + return log_level_to_file (log_level); } typedef struct { @@ -1296,7 +1295,8 @@ g_logv (const gchar *log_domain, { gboolean was_fatal = (log_level & G_LOG_FLAG_FATAL) != 0; gboolean was_recursion = (log_level & G_LOG_FLAG_RECURSION) != 0; - gchar buffer[1025], *msg, *msg_alloc = NULL; + char buffer[1025], *msg_alloc = NULL; + const char *msg; gint i; log_level &= G_LOG_LEVEL_MASK; @@ -1314,7 +1314,9 @@ g_logv (const gchar *log_domain, msg = buffer; } else - msg = msg_alloc = g_strdup_vprintf (format, args); + { + msg = format_string (format, args, &msg_alloc); + } if (expected_messages) { @@ -1482,7 +1484,7 @@ log_level_to_priority (GLogLevelFlags log_level) return "5"; } -static FILE * +static inline FILE * log_level_to_file (GLogLevelFlags log_level) { if (gmessages_use_stderr) @@ -1638,6 +1640,12 @@ done_query: * the code which sets them. For example, custom keys from GLib all have a * `GLIB_` prefix. * + * Note that keys that expect UTF-8 strings (specifically `"MESSAGE"` and + * `"GLIB_DOMAIN"`) must be passed as NUL-terminated UTF-8 strings until GLib + * version 2.74.1 because the default log handler did not consider the length of + * the `GLogField`. Starting with GLib 2.74.1 this is fixed and + * non-NUL-terminated UTF-8 strings can be passed with their correct length. + * * The @log_domain will be converted into a `GLIB_DOMAIN` field. @log_level will * be converted into a * [`PRIORITY`](https://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html#PRIORITY=) @@ -1779,7 +1787,7 @@ g_log_structured (const gchar *log_domain, } else { - message = message_allocated = g_strdup_vprintf (format, args); + message = format_string (format, args, &message_allocated); } /* Add MESSAGE, PRIORITY and GLIB_DOMAIN. */ @@ -2023,7 +2031,7 @@ g_log_structured_standard (const gchar *log_domain, } else { - fields[4].value = message_allocated = g_strdup_vprintf (message_format, args); + fields[4].value = format_string (message_format, args, &message_allocated); } va_end (args); @@ -2092,12 +2100,7 @@ g_log_writer_supports_color (gint output_fd) { #ifdef G_OS_WIN32 gboolean result = FALSE; - -#if (defined (_MSC_VER) && _MSC_VER >= 1400) - _invalid_parameter_handler oldHandler, newHandler; - int prev_report_mode = 0; -#endif - + GWin32InvalidParameterHandler handler; #endif g_return_val_if_fail (output_fd >= 0, FALSE); @@ -2124,17 +2127,7 @@ g_log_writer_supports_color (gint output_fd) */ #ifdef G_OS_WIN32 -#if (defined (_MSC_VER) && _MSC_VER >= 1400) - /* Set up our empty invalid parameter handler, for isatty(), - * in case of bad fd's passed in for isatty(), so that - * msvcrt80.dll+ won't abort the program - */ - newHandler = myInvalidParameterHandler; - oldHandler = _set_invalid_parameter_handler (newHandler); - - /* Disable the message box for assertions. */ - prev_report_mode = _CrtSetReportMode(_CRT_ASSERT, 0); -#endif + g_win32_push_empty_invalid_parameter_handler (&handler); if (g_win32_check_windows_version (10, 0, 0, G_WIN32_OS_ANY)) { @@ -2166,10 +2159,7 @@ g_log_writer_supports_color (gint output_fd) result = win32_is_pipe_tty (output_fd); reset_invalid_param_handler: -#if defined (_MSC_VER) && (_MSC_VER >= 1400) - _CrtSetReportMode(_CRT_ASSERT, prev_report_mode); - _set_invalid_parameter_handler (oldHandler); -#endif + g_win32_pop_invalid_parameter_handler (&handler); return result; #else @@ -2223,32 +2213,10 @@ gboolean g_log_writer_is_journald (gint output_fd) { #if defined(__linux__) && !defined(__BIONIC__) - /* FIXME: Use the new journal API for detecting whether we’re writing to the - * journal. See: https://github.com/systemd/systemd/issues/2473 - */ - union { - struct sockaddr_storage storage; - struct sockaddr sa; - struct sockaddr_un un; - } addr; - socklen_t addr_len; - int err; - - if (output_fd < 0) - return FALSE; - - /* Namespaced journals start with `/run/systemd/journal.${name}/` (see - * `RuntimeDirectory=systemd/journal.%i` in `systemd-journald@.service`. The - * default journal starts with `/run/systemd/journal/`. */ - memset (&addr, 0, sizeof (addr)); - addr_len = sizeof(addr); - err = getpeername (output_fd, &addr.sa, &addr_len); - if (err == 0 && addr.storage.ss_family == AF_UNIX) - return (g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal/") || - g_str_has_prefix (addr.un.sun_path, "/run/systemd/journal.")); -#endif - + return _g_fd_is_journal (output_fd); +#else return FALSE; +#endif } static void escape_string (GString *string); @@ -2286,6 +2254,8 @@ g_log_writer_format_fields (GLogLevelFlags log_level, gsize i; const gchar *message = NULL; const gchar *log_domain = NULL; + gssize message_length = -1; + gssize log_domain_length = -1; gchar level_prefix[STRING_BUFFER_SIZE]; GString *gstring; gint64 now; @@ -2299,9 +2269,15 @@ g_log_writer_format_fields (GLogLevelFlags log_level, const GLogField *field = &fields[i]; if (g_strcmp0 (field->key, "MESSAGE") == 0) - message = field->value; + { + message = field->value; + message_length = field->length; + } else if (g_strcmp0 (field->key, "GLIB_DOMAIN") == 0) - log_domain = field->value; + { + log_domain = field->value; + log_domain_length = field->length; + } } /* Format things. */ @@ -2327,7 +2303,7 @@ g_log_writer_format_fields (GLogLevelFlags log_level, if (log_domain != NULL) { - g_string_append (gstring, log_domain); + g_string_append_len (gstring, log_domain, log_domain_length); g_string_append_c (gstring, '-'); } g_string_append (gstring, level_prefix); @@ -2357,7 +2333,7 @@ g_log_writer_format_fields (GLogLevelFlags log_level, GString *msg; const gchar *charset; - msg = g_string_new (message); + msg = g_string_new_len (message, message_length); escape_string (msg); if (g_get_console_charset (&charset)) @@ -3163,6 +3139,7 @@ _g_log_fallback_handler (const gchar *log_domain, write_string (stream, level_prefix); write_string (stream, ": "); write_string (stream, message); + write_string (stream, "\n"); } static void @@ -3309,29 +3286,95 @@ g_log_default_handler (const gchar *log_domain, /** * g_set_print_handler: - * @func: the new print handler + * @func: (nullable): the new print handler or %NULL to + * reset to the default * - * Sets the print handler. + * Sets the print handler to @func, or resets it to the + * default GLib handler if %NULL. * * Any messages passed to g_print() will be output via - * the new handler. The default handler simply outputs - * the message to stdout. By providing your own handler + * the new handler. The default handler outputs + * the encoded message to stdout. By providing your own handler * you can redirect the output, to a GTK+ widget or a * log file for example. * - * Returns: the old print handler + * Since 2.76 this functions always returns a valid + * #GPrintFunc, and never returns %NULL. If no custom + * print handler was set, it will return the GLib + * default print handler and that can be re-used to + * decorate its output and/or to write to stderr + * in all platforms. Before GLib 2.76, this was %NULL. + * + * Returns: (not nullable): the old print handler */ GPrintFunc g_set_print_handler (GPrintFunc func) { - GPrintFunc old_print_func; + return g_atomic_pointer_exchange (&glib_print_func, + func ? func : g_default_print_func); +} + +static void +print_string (FILE *stream, + const gchar *string) +{ + const gchar *charset; + int ret; - g_mutex_lock (&g_messages_lock); - old_print_func = glib_print_func; - glib_print_func = func; - g_mutex_unlock (&g_messages_lock); + if (g_get_console_charset (&charset)) + { + /* charset is UTF-8 already */ + ret = fputs (string, stream); + } + else + { + gchar *converted_string = strdup_convert (string, charset); + + ret = fputs (converted_string, stream); + g_free (converted_string); + } + + /* In case of failure we can just return early, but there's nothing else + * we can do at this level + */ + if (ret == EOF) + return; + + fflush (stream); +} + +G_ALWAYS_INLINE static inline const char * +format_string (const char *format, + va_list args, + char **out_allocated_string) +{ +#ifdef G_ENABLE_DEBUG + g_assert (out_allocated_string != NULL); +#endif - return old_print_func; + /* If there is no formatting to be done, avoid an allocation */ + if (strchr (format, '%') == NULL) + { + *out_allocated_string = NULL; + return format; + } + else + { + *out_allocated_string = g_strdup_vprintf (format, args); + return *out_allocated_string; + } +} + +static void +g_default_print_func (const gchar *string) +{ + print_string (stdout, string); +} + +static void +g_default_printerr_func (const gchar *string) +{ + print_string (stderr, string); } /** @@ -3340,7 +3383,7 @@ g_set_print_handler (GPrintFunc func) * @...: the parameters to insert into the format string * * Outputs a formatted message via the print handler. - * The default print handler simply outputs the message to stdout, without + * The default print handler outputs the encoded message to stdout, without * appending a trailing new-line character. Typically, @format should end with * its own new-line character. * @@ -3355,64 +3398,49 @@ g_print (const gchar *format, ...) { va_list args; - gchar *string; + const gchar *string; + gchar *free_me = NULL; GPrintFunc local_glib_print_func; g_return_if_fail (format != NULL); va_start (args, format); - string = g_strdup_vprintf (format, args); + string = format_string (format, args, &free_me); va_end (args); - g_mutex_lock (&g_messages_lock); - local_glib_print_func = glib_print_func; - g_mutex_unlock (&g_messages_lock); - - if (local_glib_print_func) - local_glib_print_func (string); - else - { - const gchar *charset; - - if (g_get_console_charset (&charset)) - fputs (string, stdout); /* charset is UTF-8 already */ - else - { - gchar *lstring = strdup_convert (string, charset); - - fputs (lstring, stdout); - g_free (lstring); - } - fflush (stdout); - } - g_free (string); + local_glib_print_func = g_atomic_pointer_get (&glib_print_func); + local_glib_print_func (string); + g_free (free_me); } /** * g_set_printerr_handler: - * @func: the new error message handler + * @func: (nullable): he new error message handler or %NULL + * to reset to the default * - * Sets the handler for printing error messages. + * Sets the handler for printing error messages to @func, + * or resets it to the default GLib handler if %NULL. * * Any messages passed to g_printerr() will be output via - * the new handler. The default handler simply outputs the + * the new handler. The default handler outputs the encoded * message to stderr. By providing your own handler you can * redirect the output, to a GTK+ widget or a log file for * example. * - * Returns: the old error message handler + * Since 2.76 this functions always returns a valid + * #GPrintFunc, and never returns %NULL. If no custom error + * print handler was set, it will return the GLib default + * error print handler and that can be re-used to decorate + * its output and/or to write to stderr in all platforms. + * Before GLib 2.76, this was %NULL. + * + * Returns: (not nullable): the old error message handler */ GPrintFunc g_set_printerr_handler (GPrintFunc func) { - GPrintFunc old_printerr_func; - - g_mutex_lock (&g_messages_lock); - old_printerr_func = glib_printerr_func; - glib_printerr_func = func; - g_mutex_unlock (&g_messages_lock); - - return old_printerr_func; + return g_atomic_pointer_exchange (&glib_printerr_func, + func ? func : g_default_printerr_func); } /** @@ -3421,7 +3449,7 @@ g_set_printerr_handler (GPrintFunc func) * @...: the parameters to insert into the format string * * Outputs a formatted message via the error message handler. - * The default handler simply outputs the message to stderr, without appending + * The default handler outputs the encoded message to stderr, without appending * a trailing new-line character. Typically, @format should end with its own * new-line character. * @@ -3434,37 +3462,19 @@ g_printerr (const gchar *format, ...) { va_list args; - gchar *string; + const char *string; + char *free_me = NULL; GPrintFunc local_glib_printerr_func; g_return_if_fail (format != NULL); va_start (args, format); - string = g_strdup_vprintf (format, args); + string = format_string (format, args, &free_me); va_end (args); - g_mutex_lock (&g_messages_lock); - local_glib_printerr_func = glib_printerr_func; - g_mutex_unlock (&g_messages_lock); - - if (local_glib_printerr_func) - local_glib_printerr_func (string); - else - { - const gchar *charset; - - if (g_get_console_charset (&charset)) - fputs (string, stderr); /* charset is UTF-8 already */ - else - { - gchar *lstring = strdup_convert (string, charset); - - fputs (lstring, stderr); - g_free (lstring); - } - fflush (stderr); - } - g_free (string); + local_glib_printerr_func = g_atomic_pointer_get (&glib_printerr_func); + local_glib_printerr_func (string); + g_free (free_me); } /** |