Macros are often used to generalize several segments of code which might be used multiple times in the code. This guideline focuses on the macros consisting of single statements which do not usually require to be enclose in a do()....while()
. (See also PRE10-C. Wrap multi-statement macros in a do-while loop.)
When writing macros, a good C programmer should not include semicolon at the end of macro definition. The use of semicolon should be taken care while usage of the macro. The trailing semicolon at the end of the macro definition can sometimes change the control flow of the program depending upon its usage in the program code.
Other ways to avoid this kind of problem would be 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++); main() { int i; FOR_LOOP(3) { printf("Inside for loop\n"); } }
The user assumes to get the following output from the code:
Inside for loop
Inside for loop
Inside for loop
But unfortunately because of the semicolon
at the end of the macro definition, the for loop in the program has a null statement and then 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 be used in code so often by programmers, it shows the side effect a semicolon
in macro definition can have.
Compliant Solution
The compliant solution would be to write the macro definitions without the semicolon
at the end and leaving the decision to have a semicolon
or not up to the user who is using the macro.
#define FOR_LOOP(n) for(i=0; i<(n); i++) main() { int i; FOR_LOOP(3) { printf("Inside for loop\n"); } }
Noncompliant Code Example
In the code below, the programmer defines a macro which increments the value in the argument 1 by one and then wraps it along the max value provided by the user.
#define INCREMENT(x, max) ((x) = ((x) + 1) % (max)); main() { int index = 0; int value; value = INCREMENT(index, 10) + 2; ........... ........... }
In the above code, the programmer intends to increment the index and then use that as a value by adding 2
to it. Unfortunately the value will always be equal to the incremented value of index because of the semicolon
present at the end of the macro. The '+ 2;'
will be treated as another statement by the compiler. The user will not get any compilation errors. If the user has not enabled warnings while compiling, the effect of semicolon
in the macro can not be detected at an early stage.
Compliant Solution
The compliant solution would be to write the macro definitions without the semicolon
at the end and leaving the decision to have a semicolon
or not up to the user while using the macro.
#define INCREMENT(x, max) ((x) = ((x) + 1) % (max)) main() { int index = 0; int value; value = INCREMENT(index, 10) + 2; ......... .......... }
Mitigation Strategies
The programmer should ensure that there is no semicolon
at the end of the macro definition with single statement. The responsibility of having a semicolon
where needed during the use of the macro should be given to the user using the macro.
Risk Assessment
Using semicolon at the end of the 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.