7

All versions of varargs.h and/or stdarg.h I've seen either define va_end as an empty macro or some opaque compiler-specific function that I guess doesn't do anything either. The rationale in the C standard states "some implementations might need it", but gives no more details.

When would there be a real need for a va_end()? Any examples of ABI that would require such, preferably with an explanation?

user3840170
  • 26,597
  • 4
  • 30
  • 62
vonbrand
  • 11,412
  • 8
  • 32
  • 52
  • The question was closed as a near-duplicate on *when* `va_end` should be called. Not my question (I know it should be called always--just in case it does something non-trivial). I'm curious *what* ABI would require a non-trivial `va_end`. – vonbrand Aug 10 '21 at 16:37
  • The third answer in the duplicate explains an ABI that might require a non-empty implementation of `va_end`. The ABI doesn't actually specify how varargs are implemented. So the answer would be some implementation that stores the args not on the stack – Ajay Brahmakshatriya Aug 10 '21 at 16:53
  • 1
    @AjayBrahmakshatriya: Which is the "third answer"? People can sort them differently. But anyway, none of those answers actually do so, as far as I can tell. greyfade vaguely says mixed stack/register ABIs "may be more complicated" but doesn't explain where `va_end` would be needed. Maxim explains why x86-64 SysV needs `va_copy` but not `va_end`. James Curran just says "on platforms which have less traditional schemes, it becomes necessary" without elaborating which platforms or why. I am voting to reopen this. – Nate Eldredge Aug 10 '21 at 17:07
  • 2
    I could imagine a "user space" implementation which doesn't have special compiler support, and that needs some variable amount of scratch space, but doesn't have access to VLAs or `alloca`. It might be forced to get it from `malloc`, and then `va_end()` could do the `free()`. – Nate Eldredge Aug 10 '21 at 17:12
  • 1
    Now that this is no longer a dupicate... where's the "original" question? – Tim Randall Aug 10 '21 at 17:47

2 Answers2

6

Older versions of Fabrice Bellard's tcc implemented va_start() using malloc() and va_end() using free(): so failing to call va_end() would leak memory. See here. This is because it made va_list a pointer to a structure, and malloc()/free() (or technically compiler builtins for them) were used to allocate/free the structure. In newer versions of tcc, va_list is now a single-element array of a structure instead of a pointer, and hence va_end() is now effectively a no-op, like it normally is.

Simon Kissane
  • 4,373
  • 3
  • 34
  • 59
-1

C has been around for a long, long time and has many standards. These standards tend to give compilers some leeway, letting them implement their own padding/headers/etc. for performance and other reasons. I assume this was added because, as mentioned, "some compilers might need it." Though languages try to abstract their implementation details, some things - inevitably - slip through the cracks... Hope this was helpful =]

GooseDeveloper
  • 97
  • 1
  • 11