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

Не вызывайте va_arg () на va_list, который имеет неопределенное значение

Описание

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

Не вызывайте va_arg () на va_list, который имеет неопределенное значение. [1]

Примеры

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

Описание

Недопустимый va_list аргумент происходит, когда вы используете переменную va_list в качестве аргумента к функции в группе vprintf, но:

  • Вы не инициализируете переменную ранее с помощью va_start или va_copy.

  • Вы делаете недействительным переменную ранее с помощью va_end и не повторно инициализируете его.

Например, вы вызываете функциональный vsprintf как vsprintf (buffer,format, args). Однако перед вызовом функции, вы не инициализируете переменную va_list args с помощью любого из следующего:

  • va_start(args, paramName). paramName является последним параметром, передаваемым по имени функции аргумента переменной. Например, для функционального определения void func(int n, char c, ...) {}, c является последним параметром, передаваемым по имени.

  • va_copy(args, anotherList). anotherList является другой допустимой переменной va_list.

Риск

Поведение неинициализированного аргумента va_list не определено. Вызывание функции с неинициализированным аргументом va_list может вызвать переполнения стека.

Фиксация

Перед использованием переменной va_list как аргумент функции инициализируйте его с va_start или va_copy.

Очистите переменную с помощью va_end только после всего использования переменной.

Пример - переменная va_list, используемая после вызова va_end

#include <stdarg.h>
#include <stdio.h>

int call_vfprintf(int line, const char *format, ...) {
    va_list ap;
    int r=0;
    
    va_start(ap, format);
    r = vfprintf(stderr, format, ap);
    va_end(ap);

    r += vfprintf(stderr, format, ap);
    return r;
}

В этом примере переменная va_list ap используется в функции vfprintf, после того, как макрос va_end будет назван.

Исправление — вызывает va_end после Используя переменную va_list

Одно возможное исправление должно вызвать va_end только после всего использования переменной va_list.

#include <stdarg.h>
#include <stdio.h>

int call_vfprintf(int line, const char *format, ...) {
    va_list ap;
    int r=0;
    
    va_start(ap, format);
    r = vfprintf(stderr, format, ap);
    r += vfprintf(stderr, format, ap);
    va_end(ap);
    
    return r;
}

Описание

Слишком много призывов 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); 

} 

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

Группа: правило 48. Разное (MSC)

Введенный в 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". УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИЙ НИКАКОГО ВИДА, ИЛИ ВЫРАЗИЛ ИЛИ ПОДРАЗУМЕВАЛ, ОТНОСИТЕЛЬНО ЛЮБОГО ВОПРОСА ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИЛ, ГАРАНТИЯ ПРИГОДНОСТИ ДЛЯ ЦЕЛИ ИЛИ ВЫСОКОГО СПРОСА, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ ЗАКАНЧИВАЕТСЯ ПОЛУЧЕННЫЙ ИЗ ИСПОЛЬЗОВАНИЯ МАТЕРИАЛА. УНИВЕРСИТЕТ КАРНЕГИ-МЕЛЛОН НЕ ДАЕТ ГАРАНТИИ НИКАКОГО ВИДА ОТНОСИТЕЛЬНО СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКОГО ПРАВА.

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