Main Content

CERT C: Rule PRE31-C

Avoid side effects in arguments to unsafe macros

Description

Rule Definition

Avoid side effects in arguments to unsafe macros.1

Polyspace Implementation

The rule checker checks for Side effect in arguments to unsafe macro.

Examples

expand all

Issue

Side effect in arguments to unsafe macro occurs when you call an unsafe macro with an expression that has a side effect.

  • Unsafe macro: When expanded, an unsafe macro evaluates its arguments multiple times or does not evaluate its argument at all.

    For instance, the ABS macro evaluates its argument x twice.

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

  • Side effect: When evaluated, an expression with a side effect modifies at least one of the variables in the expression.

    For instance, ++n modifies n, but n+1 does not modify n.

    The checker does not consider side effects in nested macros. The checker also does not consider function calls or volatile variable access as side effects.

Risk

If you call an unsafe macro with an expression that has a side effect, the expression is evaluated multiple times or not evaluated at all. The side effect can occur multiple times or not occur at all, causing unexpected behavior.

For instance, in the call MACRO(++n), you expect only one increment of the variable n. If MACRO is an unsafe macro, the increment happens more than once or does not happen at all.

The checker flags expressions with side effects in the assert macro because the assert macro is disabled in non-debug mode. To compile in non-debug mode, you define the NDEBUG macro during compilation. For instance, in GCC, you use the flag -DNDEBUG.

Fix

Evaluate the expression with a side effect in a separate statement, and then use the result as a macro argument.

For instance, instead of:

MACRO(++n);
perform the operation in two steps:
++n;
MACRO(n);
Alternatively, use an inline function instead of a macro. Pass the expression with side effect as argument to the inline function.

The checker considers modifications of a local variable defined only in the block scope of a macro body as a side effect. This defect cannot happen since the variable is visible only in the macro body. If you see a defect of this kind, ignore the defect.

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

In this example, the ABS macro evaluates its argument twice. The second evaluation can result in an unintended increment.

Correction — Separate Evaluation of Expression from Macro Usage

One possible correction is to first perform the increment, and then pass the result to the macro.

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

Another possible correction is to evaluate the expression in an inline function.

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);
 
  /* ... */
}

Check Information

Group: Rule 01. Preprocessor (PRE)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.