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);
}
The va_start macro инициализирует список аргументов переменной, чтобы дополнительные аргументы в переменную функцию после фиксированных параметров могли быть захвачены в списке. Согласно стандартам 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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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