Avoid address wraparound inside system functions.
authorBruno Haible <bruno@clisp.org>
Mon, 2 Jul 2007 00:56:18 +0000 (00:56 +0000)
committerBruno Haible <bruno@clisp.org>
Mon, 2 Jul 2007 00:56:18 +0000 (00:56 +0000)
ChangeLog
lib/sprintf.c
lib/vsprintf.c
modules/sprintf-posix
modules/vsprintf-posix

index d84ab35..dc954fb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-07-01  Bruno Haible  <bruno@clisp.org>
+
+       * lib/sprintf.c (sprintf): Limit the available length estimation,
+       to avoid address wraparound.
+       * lib/vsprintf.c (vsprintf): Likewise.
+       * modules/sprintf-posix (Dependencies): Add stdint.
+       * modules/vsprintf-posix (Dependencies): Likewise.
+
 2007-07-01  Bruno Haible <bruno@clisp.org>
 
        * gnulib-tool (self_abspathname): Determine PATH_SEPARATOR and handle
index ab14107..035fe21 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "vasnprintf.h"
@@ -46,11 +47,19 @@ sprintf (char *str, const char *format, ...)
 {
   char *output;
   size_t len;
-  /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
-     than INT_MAX (if that fits into a 'size_t' at all).  */
-  size_t lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
+  size_t lenbuf;
   va_list args;
 
+  /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
+     than INT_MAX (if that fits into a 'size_t' at all).
+     Also note that glibc's iconv fails with E2BIG when we pass a length that
+     is so large that str + lenbuf wraps around, i.e.
+     (uintptr_t) (str + lenbuf) < (uintptr_t) str.
+     Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1).  */
+  lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
+  if (lenbuf > ~ (uintptr_t) str)
+    lenbuf = ~ (uintptr_t) str;
+
   va_start (args, format);
   output = vasnprintf (str, &lenbuf, format, args);
   len = lenbuf;
index a9d840d..88e528d 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "vasnprintf.h"
@@ -46,9 +47,17 @@ vsprintf (char *str, const char *format, va_list args)
 {
   char *output;
   size_t len;
+  size_t lenbuf;
+
   /* vasnprintf fails with EOVERFLOW when the buffer size argument is larger
-     than INT_MAX (if that fits into a 'size_t' at all).  */
-  size_t lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
+     than INT_MAX (if that fits into a 'size_t' at all).
+     Also note that glibc's iconv fails with E2BIG when we pass a length that
+     is so large that str + lenbuf wraps around, i.e.
+     (uintptr_t) (str + lenbuf) < (uintptr_t) str.
+     Therefore set lenbuf = min (SIZE_MAX, INT_MAX, - (uintptr_t) str - 1).  */
+  lenbuf = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX);
+  if (lenbuf > ~ (uintptr_t) str)
+    lenbuf = ~ (uintptr_t) str;
 
   output = vasnprintf (str, &lenbuf, format, args);
   len = lenbuf;
index 7bfa94b..0ae1ef4 100644 (file)
@@ -17,6 +17,7 @@ printf-frexpl
 signbit
 fpucw
 printf-safe
+stdint
 
 configure.ac:
 gl_FUNC_SPRINTF_POSIX
index ba79781..d96745c 100644 (file)
@@ -17,6 +17,7 @@ printf-frexpl
 signbit
 fpucw
 printf-safe
+stdint
 
 configure.ac:
 gl_FUNC_VSPRINTF_POSIX