Side effect in arguments to unsafe macro

Макрос содержит аргументы, которые могут быть оценены многократно или не оценены

Описание

Этот дефект происходит, когда вы вызываете небезопасный макрос с выражением, которое имеет побочный эффект.

  • Небезопасный макрос: Когда расширено, небезопасный макрос оценивает свои аргументы многократно или не оценивает его аргумент вообще.

    Например, ABS макрос оценивает свой аргумент x дважды.

    #define ABS(x) (((x) < 0) ? -(x) : (x))

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

    Например, ++n изменяет n, но n+1 не изменяет n.

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

Риск

Если вы вызываете небезопасный макрос с выражением, которое имеет побочный эффект, выражение выполнено многократно или не оценено вообще. Побочный эффект может произойти многократно или не произойти вообще, вызвав неожиданное поведение.

Например, в вызове MACRO(++n), вы ожидаете только один шаг переменной n. Если MACRO небезопасный макрос, шаг происходит несколько раз или не происходит вообще.

Средство проверки отмечает выражения с помощью побочных эффектов в assert макрос, потому что assert макрос отключен в нережиме отладки. Чтобы скомпилировать в нережиме отладки, вы задаете NDEBUG макрос во время компиляции. Например, в GCC, вы используете флаг -DNDEBUG.

Фиксация

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

Например, вместо:

MACRO(++n);
выполните операцию на двух шагах:
++n;
MACRO(n);
В качестве альтернативы используйте подставляемую функцию вместо макроса. Передайте выражение с побочным эффектом в качестве аргумента к подставляемой функции.

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

Примеры

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

#define ABS(x) (((x) < 0) ? -(x) : (x))
  
void func(int n) {
  /* Validate that n is within the desired range */
  int m = ABS(++n);
 
  /* ... */
}

В этом примере, ABS макрос оценивает свой аргумент дважды. Вторая оценка может привести к непреднамеренному шагу.

Коррекция — отдельная оценка выражения от макро-использования

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

#define ABS(x) (((x) < 0) ? -(x) : (x))
  
void func(int n) {
  /* Validate that n is within the desired range */
  ++n;
  int m = ABS(n);
 
  /* ... */
}
Коррекция — выполняет выражение в подставляемой функции

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

static inline int iabs(int x) {
  return (((x) < 0) ? -(x) : (x));
}
  
void func(int n) {
  /* Validate that n is within the desired range */
 
int m = iabs(++n);
 
  /* ... */
}

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

Группа: Программирование
Язык: C | C++
Значение по умолчанию: Off
Синтаксис командной строки: SIDE_EFFECT_IN_UNSAFE_MACRO_ARG
Удар: Средняя
Введенный в R2018b