Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Reverted from v. 35

...

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

...

PRE31-C.

...

Never

...

invoke

...

an

...

unsafe

...

macro

...

with

...

arguments

...

containing

...

assignment,

...

increment,

...

decrement,

...

volatile

...

access,

...

or

...

function

...

call

...

,

...

PRE01-C.

...

Use

...

parentheses

...

within

...

macros

...

around

...

parameter

...

names

...

,

...

and

...

PRE02-C.

...

Macro

...

replacement

...

lists

...

should

...

be

...

parenthesized

...

.)

...

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

...

undefined

...

behavior

...

when

...

passed

...

an

...

expression

...

that

...

contains

...

side

...

effects.

{:=
Code Block
bgColor
#FFCCCC
}
#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
bgColor
#FFCCCC
}
int a = 81 / ((++i) * (++i) * (++i));
{code}

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

...

executed

...

only

...

once

...

before

...

the

...

function

...

is

...

called.

{:=
Code Block
bgColor
#ccccff
}
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
bgColor
#FFCCCC
}
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
bgColor
#ccccff
}
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
bgColor
#FFCCCC
}
#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

...

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
bgColor
#ccccff
}
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

...

MEM02-C.

...

Immediately

...

cast

...

the

...

result

...

of

...

a

...

memory

...

allocation

...

function

...

call

...

into

...

a

...

pointer

...

to

...

the

...

allocated

...

type

...

.

...

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

...

CERT

...

website

...

.

Other Languages

This rule appears in the C++ Secure Coding Standard as PRE00-CPP.

...

Prefer

...

inline

...

or

...

static

...

functions

...

to

...

function-like

...

macros

...

.

...

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

...

...

01.

...

Preprocessor

...

(PRE)

...

      01. Preprocessor (PRE)      Image Added