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 the va_start
macro and destroyed by the va_end
macro.
The new va_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.