summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2007-07-02 00:56:18 +0000
committerBruno Haible <bruno@clisp.org>2007-07-02 00:56:18 +0000
commit7c8322243bf4fe57a7f5d042182c1b5c541bdaeb (patch)
tree59db416b8cab927056efeee4868ec0e85d3defb7
parentca3910da774f8ae6c4a2b6b8a8729b10ccc97ad4 (diff)
downloadgnulib-7c8322243bf4fe57a7f5d042182c1b5c541bdaeb.tar.gz
Avoid address wraparound inside system functions.
-rw-r--r--ChangeLog8
-rw-r--r--lib/sprintf.c15
-rw-r--r--lib/vsprintf.c13
-rw-r--r--modules/sprintf-posix1
-rw-r--r--modules/vsprintf-posix1
5 files changed, 33 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index d84ab35374..dc954fb675 100644
--- 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
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