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

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

Описание

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

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

Примеры

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

Описание

Неправильный тип данных передал 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, Используемый в качестве аргумента Function Argument Type и 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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