You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 11 Next »

Macros are often used to generalize several segments of code which might be used multiple times in the code. This guideline focuses on macros consisting of single statements, which do not usually have to be enclosed in a do()-while(). (See also PRE10-C. Wrap multi-statement macros in a do-while loop.)

When writing macros, a C programmer should not include a semicolon at the end of a macro definition. The use of a semicolon should be determined when the macro is used. A semicolon at the end of a macro definition can change the control flow of the program, depending upon its usage in the program code.

Another way to avoid this problem is to prefer inline or static functions over function-like macros. (See also PRE00-C. Prefer inline or static functions to function-like macros.)

Noncompliant Code Example

This example creates a macro definition for a for loop in the program. This macro takes an integer argument which is the number of times the loop should run. The user has provided a semicolon at the end of the macro definition by mistake.

#define FOR_LOOP(n)  for(i=0; i<(n); i++);

int i;
FOR_LOOP(3)
{
  puts("Inside for loop\n");
}

The user expects to get the following output from the code:

Inside for loop
Inside for loop
Inside for loop

But because of the semicolon at the end of the macro definition, the for loop in the program has a null statement, so the statement "Inside for loop" gets printed just once. Essentially, the semicolon at the end of the macro definition changes the program control flow.

Though the above example might not actually be used in code, it shows the effect a semicolon in a macro definition can have.

Compliant Solution

The compliant solution is to write the macro definition without the semicolon at the end, leaving the decision to have a semicolon or not up to the person who is using the macro.

#define FOR_LOOP(n)  for(i=0; i<(n); i++)

int i;
FOR_LOOP(3)
{
  puts("Inside for loop\n");
}

Noncompliant Code Example

In this noncompliant code example, the programmer defines a macro which increments the value in the argument 1 by one and modulates it with the max value provided by the user.

#define INCREMENT(x, max) ((x) = ((x) + 1) % (max));

int index = 0;
int value;
value = INCREMENT(index, 10) + 2;
/* ...*/

In this case, the programmer intends to increment index and then use that as a value by adding 2 to it. Unfortunately, the value is equal to the incremented value of index because of the semicolon present at the end of the macro. The '+ 2;' is treated as a separate statement by the compiler. The user will not get any compilation errors. If the user has not enabled warnings while compiling, the effect of the semicolon in the macro cannot be detected at an early stage.

Compliant Solution

The compliant solution is to write the macro definition without the semicolon at the end, leaving the decision to have a semicolon or not up to the person who is using the macro.

#define INCREMENT(x, max) ((x) = ((x) + 1) % (max))

Mitigation Strategies

The programmer should ensure that there is no semicolon at the end of a macro definition with single statement. The responsibility for having a semicolon where needed during the use of the macro should be given to the person using the macro.

Risk Assessment

Using a semicolon at the end of a macro definition can result in the change of program control flow and thus unintended program behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

PRE11-C

medium

probable

low

P12

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.


PRE10-C. Wrap multi-statement macros in a do-while loop      01. Preprocessor (PRE)      PRE12-C. Define numeric constants in a portable way

  • No labels