Upon code review/clang-tidy runs, I came across a function with a signature like this:
void appendFoo(const char * fmt, va_list& rVaList);
I have never seen this before.
Afaik, you can pass va_list
by value (and maybe by pointer?).
This brings me to my first question: Is passing va_list
by reference legal and does it work as expected?
Anyway, appendFoo()
calls vsprintf()
in its definition and clang-tidy gave the following warning: Function 'vsprintf' is called with an uninitialized va_list argument [clang-analyzer-valist.Uninitialized]
. The definition of appendFoo()
look basically like this:
void appendFoo(const char * fmt, va_list& rVaList) {
// retracted: allocate buffer
vsprintf(buffer, fmt, rVaList);
// errorhandling
// de-allocate buffer
}
(Yes, the return value of vsprintf
is ignored and errors are "handled" another way. I'm fixing it ...)
In particular, no va_copy
, va_start
, etc. are called.
Removing the reference and passing va_list
by value, i.e. changing the signature to void appendFoo(const char * fmt, va_list rVaList);
, eliminates the clang-tidy warning.
This brings me to my second question: Is the warning produced by clang-tidy if va_list
is passed by reference a false-positive or is there is actually a problem in passing va_list
as reference?
PS: This question is not a duplicate of varargs(va_list va_start) doesn't work with pass-by-reference parameter. The OP of that question passes an argument by reference to a function taking a va_list. I'm asking about va_list itself being passed as a reference. Oh, well.
va_list
definition is unspecified : en.cppreference.com/w/c/variadic/va_list I guess an implementation is free to use something incompatible with references (although I cannot find an example). – Inapplicableva_list
at C++. But use them very carefully. On our C++ code base, string formatting functions are variadic template functions building up a type string, that is passed by to a private variadic C function. Inspired from here (but heavily enhanced afterwards): gist.github.com/deplinenoise/6297411 – InapplicableappendFoo
. – Termlessva_list
is implemented as a macro, chances are that using it with a reference could lead to unexpected results... – Vulnerableva_list
cannot be implemented as a macro, it must be a complete object type. Anyway, I asked a similar question, you may find some details in the comments of this answer: https://mcmap.net/q/826473/-va_list-passed-to-a-function-using-va_arg-is-not-working In short: since it is unclear if it is legal to use references tova_list
, use pointers tova_list
that are allowed as per C standard. – Gemstoneva_list
itself as reference, the other question talks about the second argument passed tova_start
. – Gemstoneva_list
must be a complete object type, so references to it can't behave strangely. It can't be something likevoid
(where forming a reference would be ill-formed). – Faultva_start
andva_end
is certainly a bug - it's UB to not do so. – Beggarly