...
Arguably, a decision to inline a function is a low-level optimization detail that the compiler should make without programmer input. The use of inline functions should be evaluated based on (a) how well they are supported by targeted compilers, (b) what (if any) impact they have on the performance characteristics of your system, and (c) portability concerns. Static functions are often as good as inline functions, and are supported in C90 (unlike inline functions).
Noncompliant Code Example
In this example the macro CUBE()
has undefined behavior when passed an expression that contains side effects.
...
which is undefined (see EXP30-C. Do not depend on order of evaluation between sequence points).
Compliant Solution
When the macro definition is replaced by an inline function, the side effect is only executed once before the function is called.
Code Block | ||
---|---|---|
| ||
inline int cube(int i) { return i * i * i; } /* ... */ int i = 2; int a = 81 / cube(++i); |
Noncompliant Code Example
Wiki Markup |
---|
In this noncompliant example, the programmer has written a macro called {{EXEC_BUMP()}} to call a specified function and increment a global counter \[[Dewhurst 02|AA. C References#Dewhurst 02]\]. When the expansion of a macro is used within the body of a function, as in this example, identifiers refer to the declarations in scope where the body occurs. As a result, when the macro is called in the {{aFunc()}} function, it inadvertently increments a local counter with the same name as the global variable. Note that this example violates [DCL01-C. Do not reuse variable names in subscopes]. |
...
Code Block |
---|
Called g, count = 0. |
Compliant Solution
In this compliant solution, the EXEC_BUMP()
macro is replaced by the inline function exec_bump()
. Invoking aFunc()
now (correctly) prints the value of count
ranging from 0 to 9.
...
The use of the inline function binds the identifier count to the global variable when the function body is compiled. The name cannot be re-bound to a different variable (with the same name) when the function is called.
Noncompliant Code Example
Unlike functions, the execution of macros can interleave. Consequently, two macros that are harmless in isolation can cause undefined behavior when combined in the same expression.
...
This noncompliant code example also violates EXP30-C. Do not depend on order of evaluation between sequence points.
Compliant Solution
The execution of functions, including inline functions, cannot be interleaved, so problematic orderings are not possible.
Code Block | ||
---|---|---|
| ||
inline int f(int x) { ++operations; ++calls_to_f; return 2*x; } inline int g(int x) { ++operations; ++calls_to_g; return x + 1; } /* ... */ y = f(x) + g(x); |
Platform-Specific Details
Wiki Markup |
---|
GNU C (and some other compilers) had inline functions before they were added to C99 and as a result have significantly different semantics. Richard Kettlewell has a good explanation of differences between the C99 and GNU C rules \[[Kettlewell 03|AA. C References#Kettlewell 03]\]. |
Exceptions
PRE00-EX1: Macros can be used to implement local functions (repetitive blocks of code that have access to automatic variables from the enclosing scope) that cannot be achieved with inline functions.
...
PRE00-EX5: Macro parameters exhibit call-by-name semantics, whereas functions are call by value. Macros must be used in cases where call-by-name semantics are required.
Risk Assessment
Improper use of macros may result in undefined behavior.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
PRE00-C | medium | unlikely | medium | P4 | L3 |
Automated Detection
The LDRA tool suite V 7.6.0 can detect violations of this recommendation.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
Wiki Markup |
---|
\[[FSF 05|AA. C References#FSF 05]\] Section 5.34, "[An Inline Function Is as Fast as a Macro|http://gcc.gnu.org/onlinedocs/gcc/Inline.html]" \[[Dewhurst 02|AA. C References#Dewhurst 02]\] Gotcha #26, "#define Pseudofunctions" \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Section 6.7.4, "Function specifiers" \[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "NMP Pre-processor Directives" \[[Kettlewell 03|AA. C References#Kettlewell 03]\] \[[MISRA 04|AA. C References#MISRA 04]\] Rule 19.7 \[[Summit 05|AA. C References#Summit 05]\] Question 10.4 |
...