Main Content

Incorrect data type passed to va_arg

Data type of variadic function argument does not match type in va_arg call

Description

This defect occurs 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.

Examples

expand all

#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);
    }
    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); 
}

Result Information

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

Version History

Introduced in R2018a