[glib] gmessages: Fix -Wformat warnings for g_message() and friends



commit 32cc60dbffedc537ee2d37b9de695693e7795aae
Author: Philip Withnall <withnall endlessm com>
Date:   Thu Feb 1 13:44:08 2018 +0000

    gmessages: Fix -Wformat warnings for g_message() and friends
    
    When compiling with G_LOG_USE_STRUCTURED, g_message(), g_debug(), etc.
    use g_log_structured(). The message format string and its format
    arguments are passed as the final set of arguments in a longer varargs
    list, which includes the log domain and level (and other) fields.
    Passing the message format in this way means it’s not possible for the
    compiler to know to check its format placeholders when compiling with
    -Wformat.
    
    Fix support for this by adding a new semi-private helper function,
    _g_log_structured_standard(), which only uses varargs for the message
    format and its arguments, and uses fixed arguments for the other fields.
    This is then converted to a set of GLogFields and passed to
    g_log_structured() as normal.
    
    Support for -Wformat when compiling *without* G_LOG_USE_STRUCTURED was
    never broken.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=793074

 glib/gmessages.c |   53 +++++++++++++++++++++++++++
 glib/gmessages.h |  104 +++++++++++++++++++++++-------------------------------
 2 files changed, 97 insertions(+), 60 deletions(-)
---
diff --git a/glib/gmessages.c b/glib/gmessages.c
index dfae4df..8833ff1 100644
--- a/glib/gmessages.c
+++ b/glib/gmessages.c
@@ -1976,6 +1976,59 @@ g_log_structured_array (GLogLevelFlags   log_level,
     _g_log_abort (!(log_level & G_LOG_FLAG_RECURSION));
 }
 
+/* Semi-private helper function to implement the g_message() (etc.) macros
+ * with support for G_GNUC_PRINTF so that @message_format can be checked
+ * with -Wformat. */
+void
+g_log_structured_standard (const gchar    *log_domain,
+                           GLogLevelFlags  log_level,
+                           const gchar    *file,
+                           const gchar    *line,
+                           const gchar    *func,
+                           const gchar    *message_format,
+                           ...)
+{
+  GLogField fields[] =
+    {
+      { "PRIORITY", log_level_to_priority (log_level), -1 },
+      { "CODE_FILE", file, -1 },
+      { "CODE_LINE", line, -1 },
+      { "CODE_FUNC", func, -1 },
+      /* Filled in later: */
+      { "MESSAGE", NULL, -1 },
+      /* If @log_domain is %NULL, we will not pass this field: */
+      { "GLIB_DOMAIN", log_domain, -1 },
+    };
+  gsize n_fields;
+  gchar *message_allocated = NULL;
+  gchar buffer[1025];
+  va_list args;
+
+  va_start (args, message_format);
+
+  if (log_level & G_LOG_FLAG_RECURSION)
+    {
+      /* we use a stack buffer of fixed size, since we're likely
+       * in an out-of-memory situation
+       */
+      gsize size G_GNUC_UNUSED;
+
+      size = _g_vsnprintf (buffer, sizeof (buffer), message_format, args);
+      fields[4].value = buffer;
+    }
+  else
+    {
+      fields[4].value = message_allocated = g_strdup_vprintf (message_format, args);
+    }
+
+  va_end (args);
+
+  n_fields = G_N_ELEMENTS (fields) - ((log_domain == NULL) ? 1 : 0);
+  g_log_structured_array (log_level, fields, n_fields);
+
+  g_free (message_allocated);
+}
+
 /**
  * g_log_set_writer_func:
  * @func: log writer function, which must not be %NULL
diff --git a/glib/gmessages.h b/glib/gmessages.h
index 1815186..cebdc16 100644
--- a/glib/gmessages.h
+++ b/glib/gmessages.h
@@ -282,6 +282,14 @@ void g_assert_warning         (const char *log_domain,
                               const char *pretty_function,
                               const char *expression) G_GNUC_NORETURN;
 
+GLIB_AVAILABLE_IN_2_56
+void g_log_structured_standard (const gchar    *log_domain,
+                                GLogLevelFlags  log_level,
+                                const gchar    *file,
+                                const gchar    *line,
+                                const gchar    *func,
+                                const gchar    *message_format,
+                                ...) G_GNUC_PRINTF (6, 7);
 
 #ifndef G_LOG_DOMAIN
 #define G_LOG_DOMAIN    ((gchar*) 0)
@@ -290,38 +298,26 @@ void g_assert_warning         (const char *log_domain,
 #if defined(G_HAVE_ISO_VARARGS) && !G_ANALYZER_ANALYZING
 #ifdef G_LOG_USE_STRUCTURED
 #define g_error(...)  G_STMT_START {                                            \
-                        g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,      \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__);              \
+                        g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__); \
                         for (;;) ;                                              \
                       } G_STMT_END
-#define g_message(...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE,    \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_critical(...) g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,   \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_warning(...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,    \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_info(...)     g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,       \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
-#define g_debug(...)    g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,      \
-                                          "CODE_FILE", __FILE__,                \
-                                          "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                          "CODE_FUNC", G_STRFUNC,                \
-                                          "MESSAGE", __VA_ARGS__)
+#define g_message(...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_critical(...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_warning(...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_info(...)     g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
+#define g_debug(...)    g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+                                                   __FILE__, G_STRINGIFY (__LINE__), \
+                                                   G_STRFUNC, __VA_ARGS__)
 #else
 /* for(;;) ; so that GCC knows that control doesn't go past g_error().
  * Put space before ending semicolon to avoid C++ build warnings.
@@ -351,38 +347,26 @@ void g_assert_warning         (const char *log_domain,
 #elif defined(G_HAVE_GNUC_VARARGS)  && !G_ANALYZER_ANALYZING
 #ifdef G_LOG_USE_STRUCTURED
 #define g_error(format...)   G_STMT_START {                                          \
-                               g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR,    \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format);                  \
+                               g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_ERROR, \
+                                                          __FILE__, G_STRINGIFY (__LINE__), \
+                                                          G_STRFUNC, format); \
                                for (;;) ;                                            \
                              } G_STMT_END
-#define g_message(format...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE,   \
-                                               "CODE_FILE", __FILE__,                \
-                                               "CODE_LINE", G_STRINGIFY (__LINE__),  \
-                                               "CODE_FUNC", G_STRFUNC,                \
-                                               "MESSAGE", format)
-#define g_critical(format...) g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,  \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_warning(format...)  g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,   \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_info(format...)     g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_INFO,      \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
-#define g_debug(format...)    g_log_structured (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,     \
-                                                "CODE_FILE", __FILE__,               \
-                                                "CODE_LINE", G_STRINGIFY (__LINE__), \
-                                                "CODE_FUNC", G_STRFUNC,               \
-                                                "MESSAGE", format)
+#define g_message(format...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_critical(format...) g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_warning(format...)  g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_info(format...)     g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
+#define g_debug(format...)    g_log_structured_standard (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, \
+                                                         __FILE__, G_STRINGIFY (__LINE__), \
+                                                         G_STRFUNC, format)
 #else
 #define g_error(format...)    G_STMT_START {                 \
                                 g_log (G_LOG_DOMAIN,         \


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]