Описание
Побочный эффект в аргументах к небезопасному макросу происходит, когда вы вызываете небезопасный макрос с выражением, которое имеет побочный эффект.
Небезопасный макрос: Когда расширено, небезопасный макрос оценивает свои аргументы многократно или не оценивает его аргумент вообще.
Например, макрос ABS
оценивает свой аргумент x
дважды.
#define ABS(x) (((x) < 0) ? -(x) : (x))
Побочный эффект: Когда оценено, выражение с побочным эффектом изменяет по крайней мере одну из переменных в выражении.
Например, ++n
изменяет n
, но n+1
не изменяет n
.
Средство проверки не рассматривает побочных эффектов во вложенных макросах. Средство проверки также не рассматривает вызовы функции или энергозависимый переменный доступ как побочные эффекты.
Риск
Если вы вызываете небезопасный макрос с выражением, которое имеет побочный эффект, выражение выполнено многократно или не оценено вообще. Побочный эффект может произойти многократно или не произойти вообще, вызвав неожиданное поведение.
Например, в вызове MACRO(++n)
, вы ожидаете только один шаг переменной n
. Если MACRO
является небезопасным макросом, шаг происходит несколько раз или не происходит вообще.
Средство проверки отмечает выражения с помощью побочных эффектов в макросе assert
, потому что макрос assert
отключен в нережиме отладки. Чтобы скомпилировать в нережиме отладки, вы задаете макрос NDEBUG
во время компиляции. Например, в GCC, вы используете флаг -DNDEBUG
.
Фиксация
Выполните выражение с побочным эффектом в отдельном операторе, и затем используйте результат в качестве макро-аргумента.
Например, вместо:
выполните операцию на двух шагах:
Также используйте подставляемую функцию вместо макроса. Передайте выражение с побочным эффектом в качестве аргумента к подставляемой функции.
Средство проверки считает модификации локальной переменной заданными только в области действия блока макро-тела как побочный эффект. Этого дефекта не может произойти, поскольку переменная видима только в макро-теле. Если вы видите дефект этого вида, игнорируете дефект.
Пример - макро-аргумент с побочными эффектами
#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);
/* ... */
}