Main Content

CERT C++: EXP47-C

Do not call va_arg with an argument of the incorrect type

Description

Rule Definition

Do not call va_arg with an argument of the incorrect type.1

Polyspace Implementation

The rule checker checks for these issues:

  • Incorrect data type passed to va_arg.

  • Too many va_arg calls for current argument list.

Examples

expand all

Issue

Incorrect data type passed to va_arg when the data type in a va_arg call does not match the data type of the variadic function argument that va_arg reads.

For instance, you pass an unsigned char argument to a variadic function func. Because of default argument promotion, the argument is promoted to int. When you use a va_arg call that reads an unsigned char argument, a type mismatch occurs.

void func (int n, ...) {
   ...   
   va_list args;
   va_arg(args, unsigned char);
   //...   
}

void main(void) {
   unsigned char c;
   func(1,c);
}

Risk

In a variadic function (function with variable number of arguments), you use va_arg to read each argument from the variable argument list (va_list). The va_arg use does not guarantee that there actually exists an argument to read or that the argument data type matches the data type in the va_arg call. You have to make sure that both conditions are true.

Reading an incorrect type with a va_arg call can result in undefined behavior. Because function arguments reside on the stack, you might access an unwanted area of the stack.

Fix

Make sure that the data type of the argument passed to the variadic function matches the data type in the va_arg call.

Arguments of a variadic function undergo default argument promotions. The argument data types of a variadic function cannot be determined from a prototype. The arguments of such functions undergo default argument promotions (see Sec. 6.5.2.2 and 7.15.1.1 in the C99 Standard). Integer arguments undergo integer promotion and arguments of type float are promoted to double. For integer arguments, if a data type can be represented by an int, for instance, char or short, it is promoted to an int. Otherwise, it is promoted to an unsigned int. All other arguments do not undergo promotion.

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 - char Used as Function Argument Type and va_arg argument
#include <stdarg.h>
#include <stdio.h>

unsigned char func(size_t count, ...) {
    va_list ap;
    unsigned char result = 0;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, unsigned char); //Noncompliant
    }
    va_end(ap);
    return result;
}

void func_caller(void) {
    unsigned char c = 0x12;
    (void)func(1, c);
}

In this example, func takes an unsigned char argument, which undergoes default argument promotion to int. The data type in the va_arg call is still unsigned char, which does not match the int argument type.

Correction — Use int as va_arg Argument

One possible correction is to read an int argument with va_arg.

#include <stdarg.h>
#include <stdio.h>

unsigned char func(size_t count, ...) {
    va_list ap;
    unsigned char result = 0;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int); 
    }
    va_end(ap);
    return result;
}

void func_caller(void) {
    unsigned char c = 0x12;
    (void)func(1, c); 
}
Issue

Too many va_arg calls for current argument list occurs when the number of calls to va_arg exceeds the number of arguments passed to the corresponding variadic function. The analysis raises a defect only when the variadic function is called.

Too many va_arg calls for current argument list does not raise a defect when:

  • The number of calls to va_arg inside the variadic function is indeterminate. For example, if the calls are from an external source.

  • The va_list used in va_arg is invalid.

Risk

When you call va_arg and there is no next argument available in va_list, the behavior is undefined. The call to va_arg might corrupt data or return an unexpected result.

Fix

Ensure that you pass the correct number of arguments to the variadic function.

Example - No Argument Available When Calling va_arg
#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/
int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {
/* No further argument available 
* in va_list when calling va_arg
*/	

            result += va_arg(ap, int); //Noncompliant
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100); 

}

In this example, the named argument and only one variadic argument are passed to variadic_func() when it is called inside func(). On the second call to va_arg, no further variadic argument is available in ap and the behavior is undefined.

Correction — Pass Correct Number of Arguments to Variadic Function

One possible correction is to ensure that you pass the correct number of arguments to the variadic function.

#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/

int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {

/* The correct number of arguments is
* passed to va_list when variadic_func()
* is called inside func()
*/			
            result += va_arg(ap, int); 
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100, 200); 

} 

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.