summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2011-06-21 14:09:32 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2011-07-27 14:14:28 +0100
commit798e62c8e9f5062322f7be0a60703e0431268510 (patch)
tree3afd1065f1e0806d91000cdb32cc815c37f3be9f
parent104dc9383cd17d8202430d85e49ece66be7960a5 (diff)
Cope with platforms whose vsnprintf violates both POSIX and C99
-rw-r--r--dbus/dbus-sysdeps-unix.c52
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;
}
/**