CERT C: Rule EXP47-C

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

Описание

Управляйте определением

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

Реализация Polyspace

Это средство проверки проверяет на эти проблемы:

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

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

Примеры

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

Проблема

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

Например, вы передаете unsigned char аргумент к variadic функционирует 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);
}

Риск

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

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

Фиксация

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

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

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

Пример - 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 превышает количество аргументов, переданных соответствующей функции variadic. Анализ повышает дефект только, когда функция variadic вызвана.

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

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

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

Риск

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

Фиксация

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

Пример - никакой аргумент, доступный при вызове 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 аргумент передаются variadic_func() когда это называется в func(). На втором вызове va_arg, нет далее аргумент variadic доступен в ap и поведение не определено.

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

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

#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 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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