...
Code Block | ||||
---|---|---|---|---|
| ||||
int func(int condition) { char *s = NULL; if (condition) { s = (char *)malloc(10); if (s == NULL) { /* Handle Error */ } /* Process s */ return 0; } /* ...Code that doesn't touch s */ if (s) { /* This code is unreachable */ } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
int func(int condition) { char *s = NULL; if (condition) { s = (char *)malloc(10); if (s == NULL) { /* Handle error */ } /* Process s */ } /* ... Code that doesn't touch s */ if (s) { /* This code is now reachable */ } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
int s_loop(char *s) { size_t i; size_t len = strlen(s); for (i=0; i < len; i++) { /* ...Code that doesn't change s, i, or len */ if (s[i] == '\0') { /* This code is never reached */ } } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
int s_loop(char *s) { size_t i; size_t len = strlen(s); for (i=0; i < len; i++) { /* ... */ Code that doesn't change s, i, or len */ if (s[i+1] == '\0') { /* This code is now reached */ } } return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
int *p; /* ... */ (*p)++; |
...
Another possibility is that p
is being used to reference a memory-mapped device. In this case, the variable p
should be declared as volatile
.
...
Code Block | ||||
---|---|---|---|---|
| ||||
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 1) /* Duplicated condition */ moveWindowToTheBackground(); |
Note that duplicating a condition violates this guideline only if the duplicate conditions always behave similarly...see a compliant solution below for a condition that is textually a duplicate but behaves differently.
Compliant Solution (if/else if)
...
Code Block | ||||
---|---|---|---|---|
| ||||
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 3) moveWindowToTheBackground(); |
Noncompliant Code Example (logical operators)
Compliant Solution (Conditional Side-Effects)
This code does not violate this recommendation, because even though the conditions are textually identical, they have different side effects, because the getc()
function advances the stream marker.Using the same subexpression on either side of a logical operator is almost always a mistake. In this noncompliant code example, the rightmost subexpression of the controlling expression of each if
statement has no effect.
Code Block | ||||
---|---|---|---|---|
| ||||
if (agetc() == b && a == b) { // if the first one is true, the second one is too do_x(); } if (a == c || a == c ) { // if the first one is true, the second one is too do_w(); } |
Compliant Solution (logical operators)
':')
readMoreInput();
else if (getc() == ':')
readMoreInput();
else if (getc() == ':')
readMoreInput();
|
Noncompliant Code Example (logical operators)
Using the same subexpression on either side of a logical operator is almost always a mistake. In this noncompliant code exampleIn this compliant solution, the rightmost subexpression of the controlling expression of each if
statement has been removedno effect.
Code Block | ||||
---|---|---|---|---|
| ||||
if (a == b && a == b) { // if the first one is true, the second one is too do_x(); } if (a == c || a == c ) { // if the do_w(first one is true, the second one is too do_w(); } |
Noncompliant Code Example (Unconditional Jump)
Compliant Solution (logical operators)
In this compliant solution, the rightmost subexpression of the controlling expression of each if
statement has been removed.Unconditional jump statements typically has no effect.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> for (int i = 0; i < 10; ++iif (a == b) { printf("i is %d", ido_x(); } if (a continue;== c) //{ this is meaningless; the loop would continue anywaydo_w(); } |
...
Noncompliant Code Example (Unconditional Jump)
The continue statement has been removed from this compliant solution.Unconditional jump statements typically has no effect.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdio.h> for (int i = 0; i < 10; ++i) { printf("i is %d", i); } |
Exceptions
continue; // this is meaningless; the loop would continue anyway
}
|
Compliant Solution (Unconditional Jump)
The continue statement has been removed from this compliant solution. Anchor
default
label in a switch
statement whose controlling expression has an enumerated type and that specifies labels for all enumerations of the type. (See MSC01-C. Strive for logical completeness.) Because valid values of an enumerated type include all those of its underlying integer type, unless enumeration constants are provided for all those values, the default
label is appropriate and necessary.Code Block | ||||
---|---|---|---|---|
| ||||
typedef enum { Red, Green, Blue } Color; const char* f(Color c#include <stdio.h> for (int i = 0; i < 10; ++i) { switch printf(c) { case Red: return "Red"; case Green: return "Green"; case Blue: return "Blue"; default: return "Unknown color"; /* Not dead code */ } } void g() { Color unknown = (Color)123; puts(f(unknown)); } |
...
"i is %d", i);
}
|
Exceptions
Anchor | ||||
---|---|---|---|---|
|
default
label in a switch
statement whose controlling expression has an enumerated type and that specifies labels for all enumerations of the type. (See MSC01-C. Strive for logical completeness.) Because valid values of an enumerated type include all those of its underlying integer type, unless enumeration constants are provided for all those values, the default
label is appropriate and necessary.Code Block | ||||
---|---|---|---|---|
| ||||
typedef enum { Red, Green, Blue } Color;
const char* f(Color c) {
switch (c) {
case Red: return "Red";
case Green: return "Green";
case Blue: return "Blue";
default: return "Unknown color"; /* Not dead code */
}
}
void g() {
Color unknown = (Color)123;
puts(f(unknown));
}
|
Anchor | ||||
---|---|---|---|---|
|
Anchor | ||||
---|---|---|---|---|
|
#ifdef
ed out does not violate this guideline, on the grounds that it could be subsequently used in another application, or built on a different platform.Risk Assessment
The presence of code that has no effect or is never executed can indicate logic errors that may result in unexpected behavior and vulnerabilities. Such code can be introduced into programs in a variety of ways and eliminating it can require significant analysis.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC12-C | Low | Unlikely | Medium | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| dead-assignment | Supported + partially checked | ||||||
CodeSonar |
| DIAG.UNEX.* | Code not exercised by analysis | ||||||
| NO_EFFECT
DEADCODE
UNREACHABLE | Finds statements or expressions that do not accomplish anything or statements that perform an unintended action. Can detect the specific instance where code can never be reached because of a logical contradiction or a dead "default" in Can detect the instances where code block is unreachable because of the syntactic structure of the code | |||||||
| CC2.MSC12 | Partially implemented | |||||||
GCC | 3.0 | Options detect unused local variables, nonconstant static variables and unused function parameters, or unreachable code respectively. | |||||||
Helix QAC |
| C3110, C3112, C3307, C3404, C3426, C3427 | |||||||
Klocwork |
| CWARN.NOEFFECT.SELF_ASSIGN CWARN.NOEFFECT.UCMP.GE CWARN.NOEFFECT.UCMP.GE.MACRO CWARN.NOEFFECT.UCMP.LT CWARN.NOEFFECT.UCMP.LT.MACRO CWARN.NULLCHECK.FUNCNAME EFFECT MISRA.STMT.NO_EFFECT UNREACH.GEN UNREACH.RETURN UNREACH.SIZEOF UNREACH.ENUM LA_UNUSED VA_UNUSED.GEN VA_UNUSED.INIT INVARIANT_CONDITION.UNREACH | |||||||
LDRA tool suite |
| 8 D, 65 D, 105 D, I J, 139 S, 140 S, 57 S | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_C-MSC12-a | There shall be no unreachable code in "else" block | ||||||
PC-lint Plus |
| 438, 474, 505, 522, 523, | Fully supported | ||||||
Polyspace Bug Finder |
| Checks for:
Rec. partially covered. | |||||||
RuleChecker |
| dead-assignment | Partially checked |
Risk Assessment
The presence of code that has no effect or is never executed can indicate logic errors that may result in unexpected behavior and vulnerabilities. Such code can be introduced into programs in a variety of ways and eliminating it can require significant analysis.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC12-C | Low | Unlikely | Medium | P2 | L3 |
Automated Detection
Tool
Version
Checker
Description
DIAG.UNEX.*
LANG.STRUCT.EBS
LANG.STRUCT.RC
MISC.NOEFFECT
LANG.STRUCT.UC
LANG.STRUCT.UA
LANG.STRUCT.UULABEL
LANG.STRUCT.UUMACRO
LANG.STRUCT.UUPARAM
LANG.STRUCT.UUTAG
LANG.STRUCT.UUTYPE
LANG.STRUCT.UUVAR
Code not exercised by analysis
Empty branch statement checks
Redundant condition
Function call has no effect
Unreachable code checks
Useless assignment
Unused Label
Unused Macro
Unused Parameter
Unused Tag
Unused Type
Unused Variable
NO_EFFECT
DEADCODE
UNREACHABLE
Finds statements or expressions that do not accomplish anything or statements that perform an unintended action.
Can detect the specific instance where code can never be reached because of a logical contradiction or a dead "default" in switch
statement
Can detect the instances where code block is unreachable because of the syntactic structure of the code
CC2.MSC12
Partially implemented
3.0
Options detect unused local variables, nonconstant static variables and unused function parameters, or unreachable code respectively.
EFFECT
LV_UNUSED.GEN VA_UNUSED.* UNREACH.*
Partially implemented
Code does not execute
Default case is missing and may be reached
Size argument of function in memset
family is zero
3426, 3427, 3307, 3110, 3112, 3404, 1501, 1503, 2008, 2880, 2881, 2882, 2883, 2877, 3196, 3202, 3203, 3205, 3206, 3207, 3210, 3219, 3229, 3404, 3422, 3423, 3425, 3470, 2980, 2981, 2982, 2983, 2984, 2985, 2986
SonarQube C/C++ Plugin |
|
S1764, S2589, |
S2583, |
S1116, |
S1172, S1763, S1862 |
, S1065, S1656, S2754, S1751 | |||||||||
Splint |
| | The default mode checks for unreachable code. | ||||||
| V551, V606, V649, V779 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
CVE-2014-1266 results from a violation of this rule. There is a spurious goto fail
statement on line 631 of sslKeyExchange.c. This goto
statement gets executed unconditionally, even though it is indented as if it were part of the preceding if
statement. As a result, the call to sslRawVerify()
(which would perform the actual signature verification) becomes dead code [ImperialViolet 2014].
Related Guidelines
SEI CERT C++ Coding Standard | VOID MSC12-CPP. Detect and remove code that has no effect |
ISO/IEC TR 24772 | Unspecified Functionality [BVQ] Likely Incorrect Expressions [KOA] Dead and Deactivated Code [XYQ] |
MISRA C:2012 | Rule 2.2 (required) |
Bibliography
...
[Fortify 2006] | Code Quality, "Dead Code" |
[Coverity 2007] |
...