[glibmm/wip/dboles/ustring-sprintf: 1/4] ustring: Fix warning/errors if sprintf("fmt only")



commit 99eb3b14751b01b03420736f60337eb6df3b2ccf
Author: Daniel Boles <dboles src gnome org>
Date:   Fri Jun 21 18:16:25 2019 +0100

    ustring: Fix warning/errors if sprintf("fmt only")
    
    If no args to be substituted are given, there is nothing to do, so the
    fmt string is returned as-is without substitution. This is an obvious
    case of mismatched format/args that we can check. Not doing so causes
    warnings/errors with common compiler options, as it is a security risk.
    
    For instance, -Wformat-security causes GCC to complain thusly:
    > format not a string literal and no format arguments
    
    Not passing arguments but passing a variable string that might contain
    placeholders and thus instruct the compiler to try grabbing random
    unrelated things off the stacks is obviously not something we want to do
    – nor do we want to do it any *other* time, but this is the one case we
    can obviously catch ourselves, rather than hoping any compiler does.
    
    The argument for not just static_assert()ing that sizeof...(args) >= 1
    is that this might conceivably be used in generic code where doing the
    former would be annoying, and it's easy enough to make that work anyway.
    
    https://gitlab.gnome.org/GNOME/glibmm/issues/21#note_537551

 glib/glibmm/ustring.h | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)
---
diff --git a/glib/glibmm/ustring.h b/glib/glibmm/ustring.h
index 0c1fa015..4fe58aff 100644
--- a/glib/glibmm/ustring.h
+++ b/glib/glibmm/ustring.h
@@ -724,11 +724,13 @@ public:
    *
    * Note: You must pass the correct number/types/order of arguments to match
    * the format string, as when calling <tt>printf()</tt> directly. glibmm does
-   * not check this for you. Breaking this contract invokes undefined behavior.
+   * not check this for you. Breaking this contract invokes undefined behavior
+   * and is a security risk.
    *
    * The exception is that glibmm special-cases std::string and Glib::ustring,
    * so you can pass them in positions corresponding to <tt>%s</tt> placeholders
    * without having to call their .c_str() functions; glibmm does that for you.
+   * glibmm also overloads sprintf() with @p fmt but no @p args to avoid risks.
    *
    * Said restriction also makes sprintf() unsuitable for translatable strings,
    * as translators cannot reorder the placeholders to suit their language. If
@@ -762,6 +764,20 @@ public:
   template <class... Ts>
   static inline ustring sprintf(const ustring& fmt, const Ts&... args);
 
+  /*! Overload of sprintf() for a format string only, which returns it unchanged.
+   *
+   * If no @p args to be substituted are given, there is nothing to do, so the
+   * @p fmt string is returned as-is without substitution. This is an obvious
+   * case of mismatched format/args that we can check. Not doing so causes
+   * warnings/errors with common compiler options, as it is a security risk.
+   *
+   * @param fmt The string
+   * @return The same string.
+   *
+   * @newin{2,62}
+   */
+  static inline ustring sprintf(const ustring& fmt);
+
   //! @}
 
 private:
@@ -1265,6 +1281,13 @@ inline // static
   return ustr;
 }
 
+inline // static
+  ustring
+  ustring::sprintf(const ustring& fmt)
+{
+  return fmt;
+}
+
 #endif /* DOXYGEN_SHOULD_SKIP_THIS */
 
 /** @relates Glib::ustring */


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