From 12b51b91b80b6678b7cd4208516173908edf4c6f Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 21 Jun 2011 14:09:32 +0100 Subject: [PATCH 1/2] Cope with platforms whose vsnprintf violates both POSIX and C99 --- dbus/dbus-string.c | 3 ++ dbus/dbus-sysdeps-unix.c | 52 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c index e2eb93b..ca3a670 100644 --- a/dbus/dbus-string.c +++ b/dbus/dbus-string.c @@ -1255,6 +1255,9 @@ _dbus_string_append_printf_valist (DBusString *str, /* Measure the message length without terminating nul */ len = _dbus_printf_string_upper_bound (format, args); + if (len < 0) + return FALSE; + if (!_dbus_string_lengthen (str, len)) { /* don't leak the copy */ diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index e1e1728..79d0bb5 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -2978,14 +2978,60 @@ _dbus_full_duplex_pipe (int *fd1, * * @param format a printf-style format string * @param args arguments for the format string - * @returns length of the given format string and args + * @returns length of the given format string and args, or -1 if no memory */ int _dbus_printf_string_upper_bound (const char *format, va_list args) { - char c; - return vsnprintf (&c, 1, format, args); + char static_buf[1024]; + int bufsize = sizeof (static_buf); + int len; + + len = vsnprintf (static_buf, bufsize, format, args); + + /* If vsnprintf() returned non-negative, then either the string fits in + * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf + * returns the number of characters that were needed, or this OS returns the + * truncated length. + * + * We ignore the possibility that snprintf might just ignore the length and + * overrun the buffer (64-bit Solaris 7), because that's pathological. + * If your libc is really that bad, come back when you have a better one. */ + if (len == bufsize) + { + /* This could be the truncated length (Tru64 and IRIX have this bug), + * or the real length could be coincidentally the same. Which is it? + * If vsnprintf returns the truncated length, we'll go to the slow + * path. */ + if (vsnprintf (static_buf, 1, format, args) == 1) + len = -1; + } + + /* If vsnprintf() returned negative, we have to do more work. + * HP-UX returns negative. */ + while (len < 0) + { + char *buf; + + bufsize *= 2; + + buf = dbus_malloc (bufsize); + + if (buf == NULL) + return -1; + + len = vsnprintf (buf, bufsize, format, args); + dbus_free (buf); + + /* If the reported length is exactly the buffer size, round up to the + * next size, in case vsnprintf has been returning the truncated + * length */ + if (len == bufsize) + len = -1; + } + + return len; } /** -- 1.7.5.4