Mr.C64
Mr.C64

Reputation: 42984

Is va_end required after a vsnprintf_s call?

MSDN shows this sample code snippet for vsnprintf_s:

// crt_vsnprintf_s.cpp
#include <stdio.h>
#include <wtypes.h>

void FormatOutput(LPCSTR formatstring, ...) 
{
   int nSize = 0;
   char buff[10];
   memset(buff, 0, sizeof(buff));
   va_list args;
   va_start(args, formatstring);
   nSize = vsnprintf_s( buff, _countof(buff), _TRUNCATE, formatstring, args);
   printf("nSize: %d, buff: %s\n", nSize, buff);
}

int main() {
   FormatOutput("%s %s", "Hi", "there");
   FormatOutput("%s %s", "Hi", "there!");
   FormatOutput("%s %s", "Hi", "there!!");
}

In this sample, va_start is called without a matching va_end.

Is this a doc bug in MSDN, or should we just call va_start before invoking vsnprintf_s and then let this function do the cleanup (i.e. calling va_end) for us?

BTW: I tried the above code and it works with VS2015 with Update 3, but I don't know if it's just undefined behavior...

Upvotes: 8

Views: 1524

Answers (3)

Toby Speight
Toby Speight

Reputation: 30911

Assuming that vsnprintf_s is supposed to be similar to vsnprintf, then you shouldn't expect it to invoke va_end() for you:

The functions vprintf(), vfprintf(), vdprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), dprintf(), sprintf(), snprintf(), respectively, except that they are called with a va_list instead of a variable number of arguments. These functions do not call the va_end macro. Because they invoke the va_arg macro, the value of ap is undefined after the call. See stdarg(3).

(my emphasis)

Upvotes: 1

R Sahu
R Sahu

Reputation: 206697

va_end needs to be called for every va_start. From http://en.cppreference.com/w/c/variadic/va_end:

If there is no corresponding call to va_start or va_copy, or if va_end is not called before a function that calls va_start or va_copy returns, the behavior is undefined.

Not only do you need va_end but you also need to make sure that your function does not return before va_end is executed if va_start or va_copy is executed.

To answer your question - yes, this is a documentation bug in MSDN.

Upvotes: 7

dbush
dbush

Reputation: 224387

From the MSDN page for va_arg, va_copy, va_end, va_start:

After all arguments have been retrieved, va_end resets the pointer to NULL. va_end must be called on each argument list that's initialized with va_start or va_copy before the function returns.

So yes, this is a documentation bug.

Upvotes: 3

Related Questions