1

I have gone through the link https://devblogs.microsoft.com/oldnewthing/20131114-00/?p=2663 for potential pitsfalls using va_list

And below code segment from the same link specifies not to use va_list in manner shown because a va_list is not directly copyable.

BOOL FormatWithFallbackLanguage(
    DWORD dwMessageId, PCTSTR pszBuffer, SIZE_T cchBuffer, va_list ap)
{
 va_list apOriginal = ap;
 // Format from the user's preferred language.
 DWORD cchResult = FormatMessage(
               FORMAT_MESSAGE_FROM_HMODULE,
               g_hinst, dwMessageId, g_preferredLangId,
               pszBuffer, cchBuffer, &ap);
 // If that didn't work, then use the fallback language.
 if (cchResult == 0) {
  cchResult = FormatMessage(
               FORMAT_MESSAGE_FROM_HMODULE,
               g_hinst, dwMessageId, g_fallbackLangId,
               pszBuffer, cchBuffer, &apOriginal);
 }
 return cchResult != 0;
}

The article in the link suggesting to use va_copy for above coding scenario. However on windows, in the header file stdarg.h , the va_copy doesn't seem to be doing anything

#define va_copy(destination, source) ((destination) = (source))

My question is that whether its safe to use va_copy in windows for va_list ? If yes, why and if not then whats the way forward?

  • It seems to me this question is more about FormatMessage so perhaps mention that in the title – M.M Mar 06 '20 at 04:19
  • Since you've tagged this with C as well as C++, it's relevant to point out that C requires you to use `va_copy()` to copy the argument list (there'd be no need for the macro otherwise). Further, you must use `va_end()` on the copied list before returning from the function (or reusing the copied list, etc). See C11 [§7.16 Variable arguments ``](http://port70.net/~nsz/c/c11/n1570.html#7.16). – Jonathan Leffler Mar 06 '20 at 04:50
  • That `va_copy` is available from Windows' `stdarg.h` means that it's intended to work; otherwise they wouldn't have bothered defining it. – jamesdlin Mar 06 '20 at 05:34
  • 1
    @jamesdlin C++ also requires those things (it defers to ISO C on this topic) – M.M Mar 06 '20 at 05:40
  • @M.M Was that reply meant for @Jonathan Leffler? I'm not sure how it matters whether it's for C conformance of C++. Shipping a broken implementation of `va_copy` is not really any more standards compliant (regardless of which standard) than not shipping `va_copy` at all... – jamesdlin Mar 06 '20 at 05:46
  • @jamesdlin Yeah it was... J-tab fails me – M.M Mar 06 '20 at 05:49
  • "However on windows, in the header file stdarg.h , the va_copy doesn't seem to be doing anything" --> It is not an _OS_ concern. It is a _compiler_ concern. Different compilers in _Windows_ can do different tings. What _compiler_ are you using? – chux - Reinstate Monica Mar 06 '20 at 06:47

2 Answers2

3

You're not supposed to look inside to see how the sausages are made. :-)

Ok, now you've looked. And you've seen that Windows is not one of those platforms whose complex calling convention requires memory allocation in a va_list. It turns out that you don't really need to use va_copy instead of simple assignment and that va_end actually does nothing. That was bad. You shouldn't have looked. Now you have to forget all that.

Because tomorrow everything might change. A new library or an update to the compiler optimisation logic, or who knows what, and all of a sudden va_copy is required, va_end prevents memory leaks, and your guilty knowledge suddenly turns out to be a dangerous error.

The standard says that you must use va_copy to copy a va_list. The standard says that you must call va_end for every initialised va_list. And you must do that. Because you can't know that it's not needed on your platform without snooping where you had no business going.

The standard library does not have to obey those rules. It can make complete knowledge of its platform and its own internals, since it only needs to work in its own environment. If something changes, the good folks who maintain the standard library will be aware of it, and they will make sure that the new version works with the new version of their compiler on their platform

So that's the deal: the implementation will guarantee that if you play by the rules, things will work. The rules are there so that implementors can deal with the peculiarities of their platform, and so that compilers can squeeze out as many optimised cycles as possible.

Sometimes it seems like cutting corners and breaking the rules won't hurt, at least not right here and right now. But don't yield to that temptation. Because if you do, you've left a time bomb in your code which will go off sooner or later.

rici
  • 234,347
  • 28
  • 237
  • 341
0

If the compiler you're using is compliant with ISO C++ then va_copy is safe to use (this is a tautology).

It's conceivable that the FormatMessage function trashes the list, but I would assume it doesn't. If it did then the other suggestion in the linked article of restarting the list wouldn't work either.

Have you tried out the suggested code? The proper usage of va_copy would be:

va_list ap2;
va_copy(ap2, ap);

DWORD cchResult = FormatMessage(
           FORMAT_MESSAGE_FROM_HMODULE,
           g_hinst, dwMessageId, g_preferredLangId,
           pszBuffer, cchBuffer, &ap);

if (cchResult == 0) 
    cchResult = FormatMessage(
           FORMAT_MESSAGE_FROM_HMODULE,
           g_hinst, dwMessageId, g_fallbackLangId,
           pszBuffer, cchBuffer, &ap2);

va_end(ap2);   
M.M
  • 138,810
  • 21
  • 208
  • 365
  • I actually didn't face any issues so far on windows but above article got a doubt about its usage. Also, the way va_copy was defined in stdarg.h increased the confusion. So was wondering if using va_list with va_copy is a safe way for windows? –  Mar 06 '20 at 04:26
  • @J.Snow the operating system does not have anything to do with the question, it is about whether or not your compiler complies with the C++ Standard. Which I can't answer obviously, but if you found that it didn't, you could file a bug report – M.M Mar 06 '20 at 04:27
  • i might appear a bit confused but just to add more, i am using visual studio 2017 for compiling code on windows. Is there anything else to check whether or not my compiler complies with the C++ Standard? –  Mar 06 '20 at 04:37
  • @J.Snow not really; if it appears to work then I wouldn't worry about it – M.M Mar 06 '20 at 05:39