Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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...

like image 653
Mr.C64 Avatar asked Oct 11 '16 15:10

Mr.C64


2 Answers

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.

like image 124
R Sahu Avatar answered Oct 13 '22 23:10

R Sahu


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.

like image 3
dbush Avatar answered Oct 14 '22 01:10

dbush