The vulnerability as described in ISO/IEC TR 24772-1:2019 clause 6.28 exists in C++.
C++ lacks a keyword to be used as an explicit terminator. Therefore, it may not be readily apparent which statements are part of a loop construct or an if statement.
Consider the following sections of code:
int foo(int a, const int *b) {
int i=0;
// . . .
0;
a = for (i=0; i<10; i++); // notice the ';' !!
{
a = a + b[i];
}int c = 0;
int x = 0;
for (int j=0; j<10; j++)
c = c + b[j];
x += c; }
At first it may appear that, after the first loop, a
will be a sum of the numbers b[0]
to b[9]
. However, even though the code is laid out so that the a = a + b[i]
code appears to be within the for loop, the “;
” at the end of the for statement causes the loop to be on a null statement (the “;
”) and the
a = a + b[i];
statement to only be executed once. Similarly, the indentation leads us to believe that that assignment to x is part of the second loop, but it is not. These mistakes may be readily apparent during development or testing. More subtle cases may not be as readily apparent leading to unexpected results.
if
statements in C++ are also susceptible to control flow problems since there isn’t a requirement in C++ for there to be an else statement for every if statement. An else
statement in C++ always belong to the most recent if
statement without an else
. However, the situation could occur where it is not readily apparent to which if
statement an else
belongs due to the way the code is indented or aligned.
Similar issues arise for if
-statements, particularly during maintenance, for example:
```{.cpp}
int a,b,i;
// . . .
if (i == 10){
a = 5;
b = 10; // added later, but correct since within the {…}
}
else
a = 10;
b = 5; // added later, intended to be part
// of the else clause
```
If the assignments to b were added later and were expected to be part of each if
and else
clause (they are indented as such), the above code is incorrect: the assignment to b
that was intended to be in the else
clause is unconditionally executed.
To avoid the vulnerability or mitigate its ill effects, C++ software developers can:
Use the avoidance mechanisms of ISO/IEC 24772-1 clause 6.28.5.
Enclose the bodies of if
, else
, while
, for
, and similar in braces. This will reduce confusion and potential problems when modifying the software.
Declare loop variables in the initializer of the loop statement
Prefer the standard library algorithms over hand-crafted loops.
Consider the use of source code auto-formatters before code reviews.
See also the C++ Core Guidelines ES.85, ES.71, ES.74, ES.1 and ES.2