Stream argument with possibly unintended side effects

Побочные эффекты аргумента потока происходят более одного раза

Описание

Этот дефект возникает при вызове getc(), putc(), getwc(), или putwc() с аргументом потока, который имеет побочные эффекты.

Аргумент Stream с возможно непреднамеренными побочными эффектами рассматривает следующие побочные эффекты Stream:

  • Любое назначение переменной потока, такого как FILE *, или любое назначение переменной более глубокого типа потока, такого как массив FILE *.

  • Любой вызов функции, которая манипулирует потоком или более глубоким типом потока.

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

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

Риск

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

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

Чтобы убедиться, что побочный эффект потока происходит только один раз, используйте отдельный оператор для аргумента потока.

Примеры

расширить все

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define fatal_error() abort()

const char* myfile = "my_file.log";

void func(void)
{
    int c;
    FILE* fptr;
    /* getc() has stream argument fptr with
    * 2 side effects: call to fopen(), and assignment
    * of fptr
    */
    c = getc(fptr = fopen(myfile, "r"));
    if (c == EOF) {
        /* Handle error */
        (void)fclose(fptr);
        fatal_error();
    }
    if (fclose(fptr) == EOF) {
        /* Handle error */
        fatal_error();
    }
}

void main(void)
{
    func();

}

В этом примере getc() вызывается с аргументом stream fptr. Аргумент stream имеет два побочных эффекта: вызов fopen() и назначение fptr. Если getc() реализован как небезопасный макрос, побочные эффекты происходят несколько раз.

Коррекция - Используйте отдельный оператор для fopen()

Одной из возможных коррекций является использование отдельного оператора для fopen(). Вызов fopen() и назначение fptr происходит в этом операторе, поэтому нет побочных эффектов, когда вы проходите fptr на getc().

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

#define fatal_error() abort()


const char* myfile = "my_file.log";

void func(void)
{
    int c;
    FILE* fptr;

    /* Separate statement for fopen()
    * before call to getc()
    */
    fptr = fopen(myfile, "r");
    if (fptr == NULL) {
        /* Handle error */
        fatal_error();
    }
    c = getc(fptr);
    if (c == EOF) {
        /* Handle error */
        (void)fclose(fptr);
        fatal_error();
    }
    if (fclose(fptr) == EOF) {
        /* Handle error */
        fatal_error();
    }
}

void main(void)
{
    func();

}

Информация о результатах

Группа: Программирование
Язык: C | C++
По умолчанию: On для рукописного кода, off для сгенерированного кода
Синтаксис командной строки : STREAM_WITH_SIDE_EFFECT
Влияние: Низкое
Введенный в R2018a