Неправильные данные о типе передали va_start

Тип данных второго аргумента к макросу va_start приводит к неопределенному поведению

Описание

Неправильные данные о типе, переданные va_start, происходят, когда второй аргумент макроса va_start имеет один из этих типов данных:

  • Тип данных, который изменяется при перенесении продвижению параметра по умолчанию.

    Например, char и short подвергаются продвижению int или unsigned int, и float подвергается продвижению double. Типы int и double не изменяются при продвижении параметра по умолчанию.

  • (C только), тип регистра или тип данных объявляются со спецификатором register.

  • (Только C++) тип справочных данных.

  • (Только C++) тип данных, который имеет нетривиального конструктора копии или нетривиального конструктора перемещения.

Риск

В функции variadic или функции с переменным количеством аргументов:

void multipleArgumentFunction(int someArg, short rightmostFixedArg, ...) {
    va_list myList;
    va_start(myList, rightmostFixedArg);
    ...
    va_end(myList);
}
Макрос va_start инициализирует список аргументов переменной так, чтобы дополнительные аргументы к функции variadic после фиксированных параметров могли быть получены в списке. Согласно C11 и C++ 14 Стандартов, если вы используете один из отмеченных типов данных для второго аргумента макроса va_start (например, rightmostFixedArg в предыдущем примере), поведение, не определены.

Если тип данных вовлекает нетривиального конструктора копии, поведение задано реализацией. Например, ли конструктор копии вызывается в вызове va_start, зависит от компилятора.

Фиксация

При использовании макроса va_start попытайтесь использовать типы int, unsigned int или double для самого правого именованного параметра функции variadic. Затем используйте этот параметр в качестве второго аргумента макроса va_start.

Например, в этом примере, самый правый именованный параметр функции variadic имеет поддерживаемый тип данных int:

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

Чтобы избежать неопределенного и заданного реализацией поведения, минимизируйте использование функций variadic. Используйте средства проверки для MISRA C:2012 Rule 17.1 или MISRA C++:2008 Rule 8-4-1, чтобы обнаружить использование функций variadic.

Примеры

развернуть все

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

В этом примере средство проверки отмечает вызов va_start в:

  • addVariableNumberOfDoubles, потому что аргумент имеет, вводит short, который подвергается продвижению параметра по умолчанию int.

  • addVariableNumberOfFloats, потому что аргумент имеет, вводит std::string, который имеет нетривиального конструктора копии.

Исправление — фиксирует тип данных для второго аргумента va_start

Убедитесь, что второй аргумент макроса va_start имеет поддерживаемый тип данных. В следующем исправленном примере:

  • В addVariableNumberOfDoubles тип данных последнего именованного параметра функции variadic изменяется на int.

  • В addVariableNumberOfFloats переключаются вторые и третьи параметры функции variadic так, чтобы типом данных последнего именованного параметра был 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;
}

Информация о результате

Группа: Программирование
Язык: C | C++
Значение по умолчанию: на
Синтаксис командной строки: VA_START_INCORRECT_TYPE
Влияние: носитель

Введенный в R2019a