Main Content

Incorrect type data passed to va_start

Data type of second argument to va_start macro leads to undefined behavior

Description

This defect occurs when the second argument of the va_start macro has one of these data types:

  • A data type that changes when undergoing default argument promotion.

    For instance, char and short undergo promotion to int or unsigned int and float undergoes promotion to double. The types int and double do not change under default argument promotion.

  • (C only) A register type or a data type declared with the register qualifier.

  • (C++ only) A reference data type.

  • (C++ only) A data type that has a nontrivial copy constructor or a nontrivial move constructor.

Risk

In a variadic function or function with variable number of arguments:

void multipleArgumentFunction(int someArg, short rightmostFixedArg, ...) {
    va_list myList;
    va_start(myList, rightmostFixedArg);
    ...
    va_end(myList);
}
The va_start macro initializes a variable argument list so that additional arguments to the variadic function after the fixed parameters can be captured in the list. According to the C11 and C++14 Standards, if you use one of the flagged data types for the second argument of the va_start macro (for instance, rightmostFixedArg in the preceding example), the behavior is undefined.

If the data type involves a nontrivial copy constructor, the behavior is implementation-defined. For instance, whether the copy constructor is invoked in the call to va_start depends on the compiler.

Fix

When using the va_start macro, try to use the types int, unsigned int or double for the rightmost named parameter of the variadic function. Then, use this parameter as the second argument of the va_start macro.

For instance, in this example, the rightmost named parameter of the variadic function has a supported data type int:

void multipleArgumentFunction(int someArg, int rightmostFixedArg, ...) {
    va_list myList;
    va_start(myList, rightmostFixedArg);
    ...
    va_end(myList);
}

To avoid undefined and implementation-defined behavior, minimize the use of variadic functions. Use the checkers for MISRA C:2012 Rule 17.1 or MISRA C++:2008 Rule 8-4-1 to detect use of variadic functions.

Examples

expand all

#include <string>
#include <cstdarg>

double addVariableNumberOfDoubles(double* weight, short num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

double addVariableNumberOfFloats(float* weight, int num, std::string s, ...) {
    float sum=0.0;
    va_list list;
    va_start(list, s);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, float);
    }
    va_end(list);
    return sum;
}

In this example, the checker flags the call to va_start in:

  • addVariableNumberOfDoubles because the argument has type short, which undergoes default argument promotion to int.

  • addVariableNumberOfFloats because the argument has type std::string, which has a nontrivial copy constructor.

Correction — Fix Data Type for Second Argument of va_start

Make sure that the second argument of the va_start macro has a supported data type. In the following corrected example:

  • In addVariableNumberOfDoubles, the data type of the last named parameter of the variadic function is changed to int.

  • In addVariableNumberOfFloats, the second and third parameters of the variadic function are switched so that data type of the last named parameter is int.

#include <string>
#include <cstdarg>

double addVariableNumberOfDoubles(double* weight, int num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

double addVariableNumberOfFloats(double* weight, std::string s, int num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num);
    for(int i=0; i < num; i++) {
        sum+=weight[i]*va_arg(list, double);
    }
    va_end(list);
    return sum;
}

Result Information

Group: Programming
Language: C | C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: VA_START_INCORRECT_TYPE
Impact: Medium

Version History

Introduced in R2019a