From 9ceda5b4082cf665b5279cc5c56ecbe4fd44fb15 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sat, 12 Jan 2019 16:41:25 -0800 Subject: [PATCH] str: Fix bugs in ds_put_c_vformat(). This code used c_vasnprintf() as if it had the same interface as vsnprintf(), but it's quite different. It is necessary to make note of its return value and possibly free it. The code previously here didn't do that, which led to memory leaks and possibly worse problems. (Fortunately this function isn't used much.) Memory leak found by Address Sanitizer. --- src/libpspp/str.c | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/src/libpspp/str.c b/src/libpspp/str.c index f31677b929..57386cbfc4 100644 --- a/src/libpspp/str.c +++ b/src/libpspp/str.c @@ -1540,25 +1540,22 @@ ds_put_c_format (struct string *st, const char *format, ...) va_end (args); } - -/* Formats FORMAT as a printf string, using fmt_func (a snprintf like function) - and appends the result to ST. */ -static void -ds_put_vformat_int (struct string *st, const char *format, va_list args_, - int (*fmt_func) (char *, size_t, const char *, va_list)) +/* Formats FORMAT as a printf string and appends the result to ST. */ +void +ds_put_vformat (struct string *st, const char *format, va_list args_) { int avail, needed; va_list args; va_copy (args, args_); avail = st->ss.string != NULL ? st->capacity - st->ss.length + 1 : 0; - needed = fmt_func (st->ss.string + st->ss.length, avail, format, args); + needed = vsnprintf (st->ss.string + st->ss.length, avail, format, args); va_end (args); if (needed >= avail) { va_copy (args, args_); - fmt_func (ds_put_uninit (st, needed), needed + 1, format, args); + vsnprintf (ds_put_uninit (st, needed), needed + 1, format, args); va_end (args); } else @@ -1571,34 +1568,27 @@ ds_put_vformat_int (struct string *st, const char *format, va_list args_, avail = st->capacity - st->ss.length + 1; va_copy (args, args_); - needed = fmt_func (ds_end (st), avail, format, args); + needed = vsnprintf (ds_end (st), avail, format, args); va_end (args); } st->ss.length += needed; } } - -static int -vasnwrapper (char *str, size_t size, const char *format, va_list ap) -{ - c_vasnprintf (str, &size, format, ap); - return size; -} - -/* Formats FORMAT as a printf string and appends the result to ST. */ -void -ds_put_vformat (struct string *st, const char *format, va_list args_) -{ - ds_put_vformat_int (st, format, args_, vsnprintf); -} - /* Formats FORMAT as a printf string, as if in the C locale, and appends the result to ST. */ void -ds_put_c_vformat (struct string *st, const char *format, va_list args_) +ds_put_c_vformat (struct string *st, const char *format, va_list args) { - ds_put_vformat_int (st, format, args_, vasnwrapper); + char buf[128]; + size_t len = sizeof buf; + char *output = c_vasnprintf (buf, &len, format, args); + if (output) + { + ds_put_cstr (st, output); + if (output != buf) + free (output); + } } /* Appends byte CH to ST. */ -- 2.30.2