Main Content

CERT C++: EXP58-CPP

Pass an object of the correct type to va_start

Description

Rule Definition

Pass an object of the correct type to va_start.1

Polyspace Implementation

The rule checker checks for Incorrect type data passed to va_start.

Examples

expand all

Issue

Incorrect type data passed to va_start 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.

Example – Incorrect Data Types for Second Argument of va_start
#include <string>
#include <cstdarg>

double addVariableNumberOfDoubles(double* weight, short num, ...) {
    double sum=0.0;
    va_list list;
    va_start(list, num); //Noncompliant
    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); //Noncompliant
    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;
}

Check Information

Group: 02. Expressions (EXP)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.