Code

utils strbuf: Copy va_lists rather than using them twice.
authorSebastian Harl <sh@tokkee.org>
Wed, 20 Mar 2013 06:30:43 +0000 (23:30 -0700)
committerSebastian Harl <sh@tokkee.org>
Wed, 20 Mar 2013 06:30:43 +0000 (23:30 -0700)
After a va_list has been passed to a function that uses va_arg(), the value of
the va_list is undefined. Thus, rather copy the list before using it for the
first time to make sure we've got a valid va_list object on the second usage.

src/utils/strbuf.c

index df3ee4b236d7f41b716cec4ca6edb1f090086286..a48f7bc5765959d38050bdf2f19c027a9765f789 100644 (file)
@@ -105,6 +105,7 @@ sdb_strbuf_destroy(sdb_strbuf_t *strbuf)
 ssize_t
 sdb_strbuf_vappend(sdb_strbuf_t *strbuf, const char *fmt, va_list ap)
 {
+       va_list aq;
        int status;
 
        if ((! strbuf) || (! fmt))
@@ -116,21 +117,27 @@ sdb_strbuf_vappend(sdb_strbuf_t *strbuf, const char *fmt, va_list ap)
                if (strbuf_resize(strbuf))
                        return -1;
 
+       /* 'ap' is invalid after calling vsnprintf; thus copy before using it */
+       va_copy(aq, ap);
        status = vsnprintf(strbuf->string + strbuf->pos,
                        strbuf->size - strbuf->pos, fmt, ap);
 
-       if (status < 0)
+       if (status < 0) {
+               va_end(aq);
                return status;
+       }
 
        if ((size_t)status >= strbuf->size - strbuf->pos) {
                strbuf_resize(strbuf);
 
                /* reset string and try again */
                strbuf->string[strbuf->pos] = '\0';
-               return sdb_strbuf_vappend(strbuf, fmt, ap);
+               status = (int)sdb_strbuf_vappend(strbuf, fmt, aq);
        }
+       else
+               strbuf->pos += (size_t)status;
 
-       strbuf->pos += (size_t)status;
+       va_end(aq);
        return (ssize_t)status;
 } /* sdb_strbuf_vappend */