What exactly is va_end for? Is it always necessary to call it?
va_end
is used to do cleanup. You don't want to smash the stack, do you?
From man va_start
:
va_end()
Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. After the call va_end(ap) the variable ap is undefined. Multiple traversals of the list, each bracketed by va_start() and va_end() are possible. va_end() may be a macro or a function.
Note the presence of the word must.
The stack could become corrupted because you don't know what va_start()
is doing. The va_*
macros are meant to be treated as black boxes. Every compiler on every platform can do whatever it wants there. It may do nothing, or it may do a lot.
Some ABIs pass the first few args in registers, and the remainder on the stack. A va_arg()
there may be more complicated. You can look up how a given implementation does varargs, which may be interesting, but in writing portable code you should treat them as opaque operations.
Is va_end required after a vsnprintf_s call?
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
orva_copy
, or ifva_end
is not called before a function that callsva_start
orva_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.
Is it okay to longjmp before calling va_end?
The C99 rationale explicitly states that va_start
may allocate memory that ends up freed by va_end
, exactly what you guessed in your question:
7.15.1.2 The
va_copy
macro[...]
30 A much simpler approach is to copy the
va_list
object used to represent processing of the arguments. However, there is no safe way to
do this in C89 because the object may include pointers to memory allocated by theva_start
macro and destroyed by theva_end
macro.
The newva_copy
macro provides this safe mechanism.[...]
So yes, you need to invoke va_end
before a longjmp
. At the very least you'd otherwise have a memory leak on such an implementation.
Supposedly Pyramid OSx had an implementation where memory allocations were performed by va_start
. Function arguments were passed in registers. This was the case even for variadic functions. It may have pre-dated ANSI C's invention of function prototypes, meaning the caller wouldn't know whether it was dealing with a variadic function. va_start
allocated memory, presumably to store the function parameter values in a way that va_arg
could easily access it. va_end
freed the allocated memory.
Its implementation of va_start
and va_end
actually required matching va_start
and va_end
syntactically, because it was one that used unbalanced braces, so ANSI C already disallowed that implementation, but the same principle could be made to work while having matching braces.
I can find very little concrete information on this implementation, it's just bits and pieces on Usenet in the late '80s, early '90s. What little I did find may be incomplete or even just plain wrong. More details are very welcome, especially by anyone who used this implementation themselves.
Does va_copy() require va_end()?
Yes, every copy and the original, requires va_end()
to be called. Your example is correct, the order of your va_end()
calls can be reversed.
From ISO/IEC 9899:201x:
7.16.1.3 The va_end macro
The va_end macro facilitates a normal return from the function whose variable
argument list was referred to by the expansion of the va_start macro, or the function
containing the expansion of the va_copy macro, that initialized the va_list ap. The
va_end macro may modify ap so that it is no longer usable (without being reinitialized
by the va_start or va_copy macro). If there is no corresponding invocation of the
va_start or va_copy macro, or if the va_end macro is not invoked before the
return, the behavior is undefined.
The last sentence states that every va_start
or va_copy
must be accompanied by an va_end
before returning.
Does the ordering of multiple va_end calls matter?
On some [old] implementations, va_start
expanded to a left brace {
followed by some declaration, and va_end
expanded to a right brace }
possibly preceded by some "finalization". Morally they should match. In practice, often but not always, order does not matter much (but in principle it does matter).
On recent GCC, these va_start
and va_end
macros expand to invocations of __builtin_va_start
& __builtin_va_end
so the compiler may care (perhaps in some future version) that these are correctly nested. See this. So the "good" order should be:
va_list va[2];
va_start(va[0], fmt);
va_start(va[1], fmt);
process(fmt, va);
va_end(va[1]);
va_end(va[0]);
In practice the order of va_end
might not matter that much.
The indentation is mine to emphasize that va_start
& va_end
are "nesting"
Of course, you need to call va_arg
to really retrieve variadic arguments (I hope that your process
is doing that). stdarg(3) explains that well (for C code):
Each invocation of
va_start()
must be matched by a corresponding
invocation ofva_end()
in the same function.
Notice the corresponding word (emphasis is mine). I believe it means that va_start
and va_end
are really nesting (at least in principle).
Does `va_end()` need to be invoked before each `return` statement in a variadic function with multiple `return` statements?
From the C Standard (7.16.1 Variable argument list access macros)
1 ... Each invocation of the va_start and va_copy macros shall be matched
by a corresponding invocation of the va_end macro in the same
function.
So if va_start
was used before any return statement and va_end
was not yet invoked then it shall be invoked.
Calling a function with va_list argument needs va_start() at the beggining?
The question is if
int max(int n, va_list vals)
Called inside the function:
int max_first(int n, ...)
Needs a
va_start(vals, n)
invocation at the body's beginning?
No, it does not and it must not, the correct pattern is as follows:
int max_first(int n, ...) {
va_list vals;
va_start(vals, n);
int rv = max(n, vals);
va_end(vals);
return rv;
}
then
int max(int n, va_list vals) {
for (int i = 0; i < n; i ++) {
int val = va_arg(vals, int);
...
}
...
}
i.e. you can call va_start
only in a function that has ...
and you need to pass in the argument immediately preceding the ...
, and each call to va_start
must be always followed by va_end
for the same value, and if you pass it to a function then you must call va_end
right afterwards without using it in the calling function; if you want to process the arguments again, you must then call va_start
again.
Can we call va_start() twice without calling va_end() in between?
C11 7.16.1/1:
[...] Each invocation of the
va_start
andva_copy
macros shall be matched by a corresponding invocation of theva_end
macro in the same function.
There's no corresponding va_end
for both of the va_start
calls so the code causes undefined behaviour, with no diagnostic required as the above quote is not part of a Constraint.
Can we call va_end without invoking va_start?
From C99 7.15.1.3/2 "The va_end
macro":
If there is no corresponding invocation of the va_start or va_copy macro, or if the va_end macro is not invoked before the return, the behavior is undefined.
Related Topics
Qthread Emits Finished() Signal But Isrunning() Returns True and Isfinished() Returns False
How to Execute Two Threads Asynchronously Using Boost
Static Constexpr' Function Called in a Constant Expression Is...An Error
Pass Multiple Arguments into Std::Thread
Weird Undefined Symbols of Static Constants Inside a Struct/Class
Why Is Name Mangling Not Standardized
"Enum Class" Emulation or Solid Alternative for Msvc 10.0
Iterating Over a Vector in Reverse Direction
Is It Ever Not Safe to Throw an Exception in a Constructor
Getter and Setter, Pointers or References, and Good Syntax to Use in C++
Constructor Conditionally Marked Explicit
Std::Map of Member Function Pointers
G++ Always Backward-Compatible with "Older" Static Libraries