diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | lib/sprintf.c | 15 | ||||
-rw-r--r-- | lib/vsprintf.c | 13 | ||||
-rw-r--r-- | modules/sprintf-posix | 1 | ||||
-rw-r--r-- | modules/vsprintf-posix | 1 |
5 files changed, 33 insertions, 5 deletions
@@ -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 diff --git a/lib/sprintf.c b/lib/sprintf.c index ab14107da6..035fe21379 100644 --- a/lib/sprintf.c +++ b/lib/sprintf.c @@ -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; diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a9d840d9c8..88e528db37 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -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; diff --git a/modules/sprintf-posix b/modules/sprintf-posix index 7bfa94b23e..0ae1ef4436 100644 --- a/modules/sprintf-posix +++ b/modules/sprintf-posix @@ -17,6 +17,7 @@ printf-frexpl signbit fpucw printf-safe +stdint configure.ac: gl_FUNC_SPRINTF_POSIX diff --git a/modules/vsprintf-posix b/modules/vsprintf-posix index ba79781a26..d96745cfc6 100644 --- a/modules/vsprintf-posix +++ b/modules/vsprintf-posix @@ -17,6 +17,7 @@ printf-frexpl signbit fpucw printf-safe +stdint configure.ac: gl_FUNC_VSPRINTF_POSIX |