]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
lib/string/sprintf.[ch]: Add [v]snprintf_()
authorAlejandro Colomar <alx@kernel.org>
Sat, 26 Aug 2023 12:54:44 +0000 (14:54 +0200)
committerIker Pedrosa <ikerpedrosam@gmail.com>
Fri, 15 Dec 2023 15:41:47 +0000 (16:41 +0100)
These functions are like [v]snprintf(3), but return -1 on truncation,
which makes it easier to test.  In fact, the API of swprintf(3), which
was invented later than snprintf(3), and is the wide-character version
of it, is identical to this snprintf_().

snprintf(3) is iseful in two cases:

-  We don't care if the output is truncated.  snprintf(3) is fine for
   those, and the return value can be ignored.  But snprintf_() is also
   fine for those.

-  Truncation is bad.  In that case, it's as bad as a hard error (-1)
   from snprintf, so merging both problems into the same error code
   makes it easier to handle errors.  Return the length if no truncation
   so that we can use it if necessary.

Not returning the whole length before truncation makes a better API,
which need not read the entire input, so it's less vulnerable to DoS
attacks when a malicious user controls the input.

Use these functions to implement SNPRINTF().

Cc: Samanta Navarro <ferivoz@riseup.net>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
lib/string/sprintf.c
lib/string/sprintf.h

index 5b421ad0ebf7a4fd681c192e66cc002429b9523a..cf3c210b513687288f688f43c4a9c264ea08e38b 100644 (file)
@@ -17,3 +17,8 @@
 extern inline int xasprintf(char **restrict s, const char *restrict fmt, ...);
 extern inline int xvasprintf(char **restrict s, const char *restrict fmt,
     va_list ap);
+
+extern inline int snprintf_(char *restrict s, size_t size,
+    const char *restrict fmt, ...);
+extern inline int vsnprintf_(char *restrict s, size_t size,
+    const char *restrict fmt, va_list ap);
index 33e0bc2d3d0199a8543b61a3d2d40a7a5700325c..748536943234da91afaa172576cf890ed12f2d48 100644 (file)
 
 
 #define SNPRINTF(s, fmt, ...)                                                 \
-({                                                                            \
-       size_t  sz_, len_;                                                    \
-                                                                              \
-       sz_ = NITEMS(s);                                                      \
-       len_ = snprintf(s, sz_, fmt __VA_OPT__(,) __VA_ARGS__);               \
-                                                                              \
-       (len_ >= sz_) ? -1 : len_;                                            \
-})
+       snprintf_(s, NITEMS(s), fmt __VA_OPT__(,) __VA_ARGS__)
 
 
 format_attr(printf, 2, 3)
@@ -35,6 +28,13 @@ inline int xasprintf(char **restrict s, const char *restrict fmt, ...);
 format_attr(printf, 2, 0)
 inline int xvasprintf(char **restrict s, const char *restrict fmt, va_list ap);
 
+format_attr(printf, 3, 4)
+inline int snprintf_(char *restrict s, size_t size, const char *restrict fmt,
+    ...);
+format_attr(printf, 3, 0)
+inline int vsnprintf_(char *restrict s, size_t size, const char *restrict fmt,
+    va_list ap);
+
 
 inline int
 xasprintf(char **restrict s, const char *restrict fmt, ...)
@@ -65,4 +65,33 @@ xvasprintf(char **restrict s, const char *restrict fmt, va_list ap)
 }
 
 
+inline int
+snprintf_(char *restrict s, size_t size, const char *restrict fmt, ...)
+{
+       int      len;
+       va_list  ap;
+
+       va_start(ap, fmt);
+       len = vsnprintf_(s, size, fmt, ap);
+       va_end(ap);
+
+       return len;
+}
+
+
+inline int
+vsnprintf_(char *restrict s, size_t size, const char *restrict fmt, va_list ap)
+{
+       int  len;
+
+       len = vsnprintf(s, size, fmt, ap);
+       if (len == -1)
+               return -1;
+       if ((size_t) len >= size)
+               return -1;
+
+       return len;
+}
+
+
 #endif  // include guard