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-07-27 14:14:28 +0100 |
commit | 798e62c8e9f5062322f7be0a60703e0431268510 (patch) | |
tree | 3afd1065f1e0806d91000cdb32cc815c37f3be9f | |
parent | 104dc9383cd17d8202430d85e49ece66be7960a5 (diff) |
Cope with platforms whose vsnprintf violates both POSIX and C99
-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 d6063713..fc0cc1c2 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -2970,14 +2970,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; } /** |