diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2011-06-21 14:09:32 +0100 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2011-09-21 11:25:48 +0100 |
commit | 7fc9c026669976463adcd1e02ad19c582ed27289 (patch) | |
tree | 0351d23409734f4d227bc501277e9c717d4f1480 | |
parent | 029ecdf40268b1c0db04bb617f067487719bf251 (diff) |
Cope with platforms whose vsnprintf violates both POSIX and C99
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=11668
Reviewed-by: Will Thompson <will.thompson@collabora.co.uk>
-rw-r--r-- | dbus/dbus-sysdeps-unix.c | 52 |
1 files changed, 49 insertions, 3 deletions
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 171977d3..f51f6fcb 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -3021,14 +3021,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; } /** |