In general, there must be a match between the number of parameters in a function call and the number of arguments in the function definition. For issues related to macro signatures, see subclause Pre-processor directives[NMP].
The number of arguments can be different to the number of parameters in a function where: - a function template includes a function parameter pack, or - a function parameter includes a default argument, or - a function parameter-declaration-clause ends with an ellipsis, f(\...)
.
Calling a function template with a function parameter pack results in a specialization of the function with the parameter types matching the corresponding argument types.
The compiler will ensure for variadic templates that the type and number of arguments is correct.
A call to a function with default arguments can provide fewer arguments than parameters as long as the parameters for which no explicit argument is provided include a default argument.
Where a function parameter-declaration-clause ends with an ellipsis, additional arguments can be accessed through the mechanisms provided by <cstdarg>
. No information about the number or types of the parameters is supplied by the compiler. The use of this feature outside of special situations can be the basis for vulnerabilities.
Undefined behavior [EWF] can arise, for example:
int
and not short
. The use of short
with va_arg
is therefore invalid.#include <cstdarg>
void f1 (int cnt, ...)
{va_list ap;
va_start (ap, cnt);
short i = va_arg (ap, short); // Invalid type
va_end(ap); }
f1
assumes that there will be two parameters after the named parameter.#include <cstdarg>
void f1 (int cnt, ...)
{va_list ap;
va_start (ap, cnt);
int i = va_arg (ap, int);
int j = va_arg (ap, int);
va_end(ap);
}
void f2 ()
{1, 2, 3); // OK
f1 (1, 2); // results in undefined behaviour
f1 ( }
These issues cannot occur where default arguments or variadic function templates are used.
The C++ Name mangling ensures that function signatures match accross translation units.
This does not apply to other mangling schemes. For example, parameters do not form part of the mangled name for functions declared with the extern "C"
linkage specification. Thus such a function can be invoked with incorrect parameter types due to an incorrect redeclaration of the function:
// library.cc
extern "C" void foo (unsigned, unsigned)
{// ...
}
// main.cc
extern "C" void foo (unsigned);
int main ()
{0xffffffff); // Calling function that is
foo (// defined to take 2 parameters
}
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Use the avoidance mechanisms of ISO/IEC TR 24772-1:2019 clause 6.34.5.
Avoid using functionality from <cstdarg>
; use variadic function templates instead.
When using functions declared with extern "C"
linkage specifications, use static analysis tools to ensure that all such declarations of equally named functions have identical signatures.
Note: See also C++ Core Guidelines F.55.