...
Macros
...
are
...
dangerous
...
because
...
their
...
use
...
resembles
...
that
...
of
...
real
...
functions,
...
but
...
they
...
have
...
different
...
semantics.
...
C99
...
adds
...
inline
...
functions
...
to
...
the
...
C
...
programming
...
language.
...
Inline
...
functions
...
should
...
be
...
preferred
...
over
...
macros
...
when
...
they
...
can
...
be
...
used
...
interchangeably.
...
Making
...
a
...
function
...
an
...
inline
...
function
...
suggests
...
that
...
calls
...
to
...
the
...
function
...
be
...
as
...
fast
...
as
...
possible
...
by
...
using,
...
for
...
example,
...
an
...
alternative
...
to
...
the
...
usual
...
function
...
call
...
mechanism,
...
such
...
as
...
inline
...
substitution
...
.
...
(See
...
also
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
,
...
...
...
...
...
...
...
...
...
,
...
and
...
...
...
...
...
...
...
...
.)
...
Inline
...
substitution
...
is
...
not
...
textual
...
substitution,
...
nor
...
does
...
it
...
create
...
a
...
new
...
function.
...
For
...
example,
...
the
...
expansion
...
of
...
a
...
macro
...
used
...
within
...
the
...
body
...
of
...
the
...
function
...
uses
...
the
...
definition
...
it
...
had
...
at
...
the
...
point
...
the
...
function
...
body
...
appeared,
...
and
...
not
...
where
...
the
...
function
...
is
...
called;
...
and
...
identifiers
...
refer
...
to
...
the
...
declarations
...
in
...
scope
...
where
...
the
...
body
...
occurs.
...
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
...
on
...
the
...
basis
...
of
...
(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
...
noncompliant
...
code
...
example,
...
the
...
macro
...
CUBE()
...
has
...
...
...
when
...
passed
...
an
...
expression
...
that
...
contains
...
side
...
effects.
Code Block | ||||
---|---|---|---|---|
| =
| |||
} #define CUBE(X) ((X) * (X) * (X)) /* ... */ int i = 2; int a = 81 / CUBE(++i); {code} |
For
...
this
...
example,
...
the
...
initialization
...
for
...
a
...
expands
...
to
Code Block | ||||
---|---|---|---|---|
| =
| |||
} int a = 81 / ((++i) * (++i) * (++i)); {code} |
which
...
is
...
undefined
...
(see
...
...
...
...
...
...
...
...
...
...
...
...
).
...
Compliant
...
Solution
...
When
...
the
...
macro
...
definition
...
is
...
replaced
...
by
...
an
...
inline
...
function,
...
the
...
side
...
effect
...
is
...
executed
...
only
...
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); {code} h2. Noncompliant Code Example |
Noncompliant Code Example
Wiki Markup |
---|
In this noncompliant code 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 also violates [DCL01-C. Do not reuse variable names in subscopes]. |
Code Block | ||||
---|---|---|---|---|
| =
| |||
} size_t count = 0; #define EXEC_BUMP(func) (func(), ++count) void g(void) { printf("Called g, count = %zu.\n", count); } void aFunc(void) { size_t count = 0; while (count++ < 10) { EXEC_BUMP(g); } } {code} |
The
...
result
...
is
...
that
...
invoking
...
aFunc()
...
(incorrectly)
...
prints
...
out
...
the
...
following
...
line
...
five
...
times:
Code Block |
---|
} Called g, count = 0. {code} h2. Compliant Solution In this compliant solution, the {{ |
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.
Code Block | ||||
---|---|---|---|---|
| =
| |||
} size_t count = 0; void g(void) { printf("Called g, count = %zu.\n", count); } typedef void (*exec_func)(void); inline void exec_bump(exec_func f) { f(); ++count; } void aFunc(void) { size_t count = 0; while (count++ < 10) { exec_bump(g); } } {code} |
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.
...
In
...
this
...
example,
...
F()
...
and
...
G()
...
both
...
increment
...
the
...
global
...
variable
...
operations
...
,
...
which
...
causes
...
problems
...
when
...
the
...
two
...
macros
...
are
...
used
...
together.
Code Block | ||||
---|---|---|---|---|
| =
| |||
} #define F(x) (++operations, ++calls_to_F, 2*x) #define G(x) (++operations, ++calls_to_G, x + 1) /* ... */ y = F(x) + G(x); {code} |
The
...
variable
...
operations
...
is
...
both
...
read
...
and
...
modified
...
twice
...
in
...
the
...
same
...
expression,
...
so
...
it
...
can
...
receive
...
the
...
wrong
...
value
...
if,
...
for
...
example,
...
the
...
following
...
ordering
...
occurs:
No Format |
---|
} read operations into register 0 read operations into register 1 increment register 0 increment register 1 store register 0 into operations store register 1 into operations {noformat} |
This
...
noncompliant
...
code
...
example
...
also
...
violates
...
...
...
...
...
...
...
...
...
...
...
...
.
...
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); {code} h3. |
Platform-Specific
...
Details
Wiki Markup |
---|
GNU C (and some other compilers) supported inline functions before they were added to C99 and as a result have significantly different semantics. Richard Kettlewell provides 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-EX2:
...
Macros
...
can
...
also
...
be
...
made
...
to
...
support
...
certain
...
forms
...
of
...
lazy
...
calculation
...
that
...
cannot
...
be
...
achieved
...
with
...
an
...
inline
...
function.
...
For
...
example,
Code Block |
---|
} #define SELECT(s, v1, v2) ((s) ? (v1) : (v2)) {code} |
calculates
...
only
...
one
...
of
...
the
...
two
...
expressions
...
depending
...
on
...
the
...
selector's
...
value.
...
PRE00-EX3:
...
Macros
...
can
...
be
...
used
...
to
...
yield
...
a
...
compile-time
...
constant.
...
This
...
is
...
not
...
always
...
possible
...
using
...
inline
...
functions,
...
as
...
shown
...
by
...
the
...
following
...
example:
Code Block |
---|
} #define ADD_M(a, b) ((a) + (b)) static inline add_f(int a, int b) { return a + b; } {code} |
In
...
this
...
example,
...
the
...
ADD_M(3,4)
...
macro
...
invocation
...
yields
...
a
...
constant
...
expression,
...
while
...
the
...
add_f(3,4)
...
function
...
invocation
...
does
...
not.
...
PRE00-EX4:
...
Macros
...
can
...
be
...
used
...
to
...
implement
...
type-generic
...
functions
...
that
...
cannot
...
be
...
implemented
...
in
...
the
...
C
...
language
...
without
...
the
...
aid
...
of
...
a
...
mechanism
...
such
...
as
...
C+
...
+
...
templates.
...
An
...
example
...
of
...
the
...
use
...
of
...
function-like
...
macros
...
to
...
create
...
type-generic
...
functions
...
is
...
shown
...
in
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
.
...
Type-generic
...
macros
...
may
...
also
...
be
...
used,
...
for
...
example,
...
to
...
swap
...
two
...
variables
...
of
...
any
...
type,
...
provided
...
they
...
are
...
of
...
the
...
same
...
type.
...
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
...
...
...
.
Other Languages
This rule appears in the C++ Secure Coding Standard as PRE00-CPP.
...
...
...
...
...
...
...
...
...
.
...
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 |
...
...
...
...
...