...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdarg.h> #include <stddef.h> void func(size_t countnum_vargs, ...) { va_list ap; va_start(ap, countnum_vargs); if (countnum_vargs > 0) { unsigned char c = va_arg(ap, unsigned char); // ... } va_end(ap); } void f(void) { unsigned char c = 0x12; func(1, c); } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdarg.h> #include <stddef.h> void func(size_t countnum_vargs, ...) { va_list ap; va_start(ap, countnum_vargs); if (countnum_vargs > 0) { unsigned char c = (unsigned char) va_arg(ap, int); // ... } va_end(ap); } void f(void) { unsigned char c = 0x12; func(1, c); } |
...
This noncompliant code example assumes that at least one variadic argument is passed to the function, and attempts to read it using the va_arg()
macro. This pattern arises frequently when a variadic function uses a sentinel value to denote the end of the variable argument list. However, the caller does not pass any extra passes no variadic arguments to the function, resulting which results in undefined behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdarg.h> void func(const char *cp, ...) { va_list ap; va_start(ap, cp); int val = va_arg(ap, int); // ... va_end(ap); } void f(void) { func("The only argument"); } |
Compliant Solution
It is not possible for the Standard C provides no mechanism to enable a variadic function to determine how many variadic arguments are actually provided to the function call; that . That information must be passed in an out-of-band waymanner. Oftentimes this results in the information being encoded in the initial parameter, as in this compliant solution:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdarg.h> #include <stddef.h> void func(size_t num_vargs, const char *cp, size_t numArgs, ...) { va_list ap; va_start(ap, cp); if (numArgsnum_vargs > 0) { int val = va_arg(ap, int); // ... } va_end(ap); } void f(void) { func(0, "The only argument", 0); } |
Risk Assessment
Incorrect use of va_arg()
results in undefined behavior that can include accessing stack memory.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
EXP47-C | Medium | Likely | High | P6 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Axivion Bauhaus Suite |
| CertC-EXP47 | |||||||
Clang |
| -Wvarargs | Can detect some instances of this rule, such as promotable types. Cannot detect mismatched types or incorrect number of variadic arguments. | ||||||
CodeSonar |
| BADMACRO.STDARG_H | Use of <stdarg.h> feature | ||||||
LDRA tool suite |
| 44 S | Enhanced Enforcement | ||||||
Parasoft C/C++test |
| CERT_C-EXP47-a | Do not call va_arg with an argument of the incorrect type | ||||||
| Checks for:
Rule fully covered | ||||||||
TrustInSoft Analyzer |
| unclassified (variadic) | Exhaustively verified (see one compliant and one non-compliant example). |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Bibliography
[ISO/IEC 9899:2011] | Subclause 7.16, "Variable Arguments <stdarg.h> "Subclause 6.5.2.2, "Function calls" |
...
...