From 798e62c8e9f5062322f7be0a60703e0431268510 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 21 Jun 2011 14:09:32 +0100 Subject: [PATCH] Cope with platforms whose vsnprintf violates both POSIX and C99 --- 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 d606371..fc0cc1c 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; } /** -- 1.7.5.4