exponenta event banner

CERT C++: EXP58-CPP

Передать объект правильного типа в va_start

Описание

Определение правила

Передать объект правильного типа в va_start.[1]

Внедрение Polyspace

Эта проверка проверяет данные неверного типа, переданные va_start.

Примеры

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

Проблема

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

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

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

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

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

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

Риск

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

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

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

Зафиксировать

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

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

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

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

Пример - Неверные типы данных для второго аргумента va_start
#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, тип данных последнего именованного параметра переменной функции изменяется на int.

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

Проверить информацию

Группа: 02. Выражения (EXP)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.