exponenta event banner

CERT C: EXP47-C правил

Не вызывать va_arg с аргументом неправильного типа

Описание

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

Не вызывайте va_arg с аргументом неправильного типа. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

  • va_arg передан неверный тип данных.

  • Слишком много вызовов va_arg для текущего списка аргументов.

Примеры

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

Проблема

Неверный тип данных передан va_arg, когда тип данных в va_arg вызов не соответствует типу данных аргумента переменной функции, va_arg читает.

Например, вы передаете unsigned char аргумент переменной функции func. Из-за продвижения аргумента по умолчанию аргумент повышается до int. При использовании va_arg вызов, который читает unsigned char , происходит несоответствие типов.

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

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

Риск

В переменной функции (функция с переменным числом аргументов) используется va_arg для считывания каждого аргумента из списка переменных аргументов (va_list). va_arg использование не гарантирует, что действительно существует аргумент для чтения или что тип данных аргумента соответствует типу данных в va_arg звоните. Вы должны убедиться, что оба условия соответствуют действительности.

Чтение неверного типа с помощью va_arg вызов может привести к неопределенному поведению. Поскольку аргументы функции находятся в стеке, можно получить доступ к нежелательной области стека.

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

Убедитесь, что тип данных аргумента, переданного переменной функции, соответствует типу данных в va_arg звоните.

Аргументы переменной функции подвергаются продвижению по умолчанию. Типы данных аргументов переменной функции не могут быть определены из прототипа. Аргументы таких функций подвергаются повышениям по умолчанию (см. разделы 6.5.2.2 и 7.15.1.1 стандарта C99). Целочисленные аргументы подвергаются целочисленному продвижению и аргументам типа float повышены до double. Для целочисленных аргументов, если тип данных может быть представлен int, например, char или short, он повышен до int. В противном случае он повышается до unsigned int. Все остальные аргументы не проходят повышение.

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

Пример - char Используется как тип аргумента функции и 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, unsigned char);
    }
    va_end(ap);
    return result;
}

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

В этом примере: func принимает unsigned char аргумент, который подвергается продвижению аргумента по умолчанию int. Тип данных в va_arg вызов по-прежнему unsigned char, который не соответствует int тип аргумента.

Коррекция - использование int как va_arg Аргумент

Одним из возможных исправлений является чтение int аргумент с 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); 
}
Проблема

Слишком много вызовов va_arg для текущего списка аргументов происходит, когда количество вызовов для va_arg превышает число аргументов, переданных соответствующей вариадной функции. Анализ вызывает дефект только при вызове вариадической функции.

Слишком много вызовов va_arg для текущего списка аргументов не вызывает дефекта, когда:

  • Количество вызовов для va_arg внутри вариадной функции является неопределенным. Например, если вызовы поступают из внешнего источника.

  • va_list используется в va_arg недопустим.

Риск

При звонке va_arg и нет следующего аргумента, доступного в va_list, поведение не определено. Вызов va_arg может повредить данные или вернуть неожиданный результат.

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

Убедитесь, что в переменную функцию передано правильное число аргументов.

Пример - При вызове аргумент недоступен 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);
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100); 

}

В этом примере именованный аргумент и только один переменный аргумент передаются variadic_func() при вызове внутри func(). По второму вызову va_arg, дальнейший вариадный аргумент не доступен в ap и поведение не определено.

Коррекция - Передача правильного количества аргументов в переменную функцию

Одной из возможных корректировок является передача правильного количества аргументов в переменную функцию.

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

} 

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

Группа: Правило 03. Выражения (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 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

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

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