Main Content

CERT C: Rec. PRE12-C

Do not define unsafe macros

Since R2024a

Description

Do not define unsafe macros1

Polyspace Implementation

The rule checker checks for Unsafe function-like macros.

Examples

expand all

Issue

A function-like macro is unsafe if its expansion causes at least one of its arguments to be evaluated either more than once or never at all. The checker reports violations on such macros.

Notes about the checker's behavior:

  • Certain expressions such as sizeof() and typeof() do not typically evaluate their arguments. The checker ignores such expressions when determining whether a certain macro violates this recommendation.

  • The checker ignores the usage of a parameter as an operand of # or ## when determining whether a certain macro violates this recommendation.

Risk

Users of an unsafe function-like macro might be unfamiliar with the implementation of the macro. They might even be unaware that they are using a macro in the first place, and expect the macro to behave like an ordinary function call.

A function call evaluates each of its arguments exactly once which minimizes unexpected side effects during argument evaluation. By contrast, the unusual semantics of unsafe function-like macros is likely to cause surprising and hard-to-find side effects and thereby introduce bugs in your code.

Fix

Make sure your function-like macros evaluate each of their arguments exactly once.

More preferably, replace function-like macros with inline or static functions. In most situations, compilers can optimize calls to such functions to improve performance. This provides much of the same benefits of using macros, while also providing the unsurprising semantics of function calls.

Example — Unsafe function-like macros
#define ABS(x) (((x) < 0) ? -(x) : (x))   /* Non-compliant */
#define NO_EVAL(x,y) ((y) + sizeof(y))    /* Non-compliant */
#define CONCAT(x) x##x                    /* Compliant */

void f(int n) {
  int m,q,qq;
  m = ABS(++n);         /* expands to: m = (((++n) < 0) ? -(++n) : (++n)); */
  q = NO_EVAL(++n,++m); /* expands to: q = ((++m) + sizeof(++m)); */
  CONCAT(q) = 0;  /* expands to: qq = 0; */
}

#undef ABS
#undef NO_EVAL
#undef CONCAT

The macro ABS violates this recommendation because the expansion of ABS evaluates its argument x two times:

  • When evaluating the expression ((x) < 0).

  • When evaluating either -(x) or (x), depending on the value of the condition.

The macro NO_EVAL evaluates its second argument y exactly once because the expression sizeof(y) does not typically evaluate its argument. However, NO_EVAL does not evaluate its first argument x at all, and therefore violates this recommendation.

The macro CONCAT uses its argument x twice with the token-pasting operator ## to create a new token xx. The expansion of this macro does not evaluate its repeated argument x and, therefore, does not violate this recommendation.

Correction — Replace macros with inline functions

To fix this violation, replace the macros ABS and NO_EVAL with equivalent inline functions.

#define CONCAT(x) x##x  /* Compliant */

inline int Abs(int x) {     
    return x < 0 ? -x : x;  
}

inline int No_Eval(int x, int y) {     
    return y + sizeof(y);  
}

void f(int n) {
  int m,q,qq;
  m = Abs(++n);         
  q = No_Eval(++n,++m);
  CONCAT(q) = 0;  /* expands to: qq = 0; */
}

#undef CONCAT

Result Information

Group: Rec. 12. Preprocessor (PRE)

Version History

Introduced in R2024a


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.