Don't bother reading this, yet. I'm still working on it... Dan
A variadic function – a function declared with a parameter list ending with ellipsis (...) – can accept a varying number of arguments of varying types. Variadic functions are flexible, but they are also hazardous. The compiler can't verify that a given call to a variadic function passes an appropriate number of arguments or that those arguments have appropriate types. Consequently, a runtime call to a variadic function that passes inappropriate arguments yields undefined behavior. Such undefined behavior could be exploited to run arbitrary code.
Non-compliant Code Example
Compliant Solution
Exceptions
When a function call appears in some contexts, notably as the argument in a sizeof expression, the compiler performs overload resolution to determine the result type of the call, but the object code doesn't execute the call at runtime. In that case, calling a variadic function does no harm, and can actually be very useful, especially when using template metaprogramming techniques that exploit SFINAE ("substitution failure is not an error").
typedef char True; typedef struct { char a[2]; } False; template <typename T> True isPtr(T *); False isPtr(...); #define is_ptr(e) (sizeof(isPtr(e)) == sizeof(True))
In this example, is_ptr(e)
returns true if expression e
has a pointer type.
Risk Assessment
Incorrectly using a variadic function can result in abnormal program termination, unintended information disclosure, or execution of arbitrary code.
Rule |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
DCL33-C |
3 (high) |
2 (probable) |
3 (low) |
P18 |
L1 |
References
[[Dewhurst 03]] Gotcha 55: Runtime Static Initialization