Main Content

CERT C: Rec. MSC12-C

Detect and remove code that has no effect or is never executed

Description

Rule Definition

Detect and remove code that has no effect or is never executed.1

Polyspace Implementation

The rule checker checks for these issues:

  • Unreachable code.

  • Dead code.

  • Useless if.

  • Write without a further read.

Examples

expand all

Issue

The issue occurs when your project contains code that is unreachable.

Risk

Unless a program exhibits any undefined behavior, unreachable code cannot execute. The unreachable code cannot affect the program output. The presence of unreachable code can indicate an error in the program logic. Unreachable code that the compiler does not remove wastes resources, for example:

  • It occupies space in the target machine memory.

  • Its presence can cause a compiler to select longer, slower jump instructions when transferring control around the unreachable code.

  • Within a loop, it can prevent the entire loop from residing in an instruction cache.

Example - Code Following return Statement
enum light { red, amber, red_amber, green };
void report_color(enum light);
enum light next_light ( enum light color )
{
    enum light res;

    switch ( color )
    {
    case red:
        res = red_amber;
        break;
    case red_amber:
        res = green;
        break;
    case green:
        res = amber;
        break;
    case amber:
        res = red;
        break;
    default:
    {
        error_handler ();
        break;
    }
    }

    report_color(res);
    return res;
    res = color;     /* Non-compliant */
}

In this example, the rule is violated because there is an unreachable operation following the return statement.

Issue

The issue occurs when the analysis detects a reachable operation that does not affect program behavior if the operation is removed.

Polyspace® Bug Finder™ detects useless write operations during analysis.

Risk

If an operation is reachable but removing the operation does not affect program behavior, the operation constitutes dead code.

The presence of dead code can indicate an error in the program logic. Because a compiler can remove dead code, its presence can cause confusion for code reviewers.

Operations involving language extensions such as __asm ( "NOP" ); are not considered dead code.

Example - Redundant Operations
extern volatile unsigned int v;
extern char *p;

void f ( void ) {
    unsigned int x;


    ( void ) v;      /* Compliant - Exception*/
    ( int ) v;       /* Non-compliant  */
    v >> 3;          /* Non-compliant  */

    x = 3;           /* Non-compliant - Detected in Bug Finder only */

    *p++;            /* Non-compliant  */
    ( *p )++;        /* Compliant  */
}

In this example, the rule is violated when an operation is performed on a variable, but the result of that operation is not used. For instance,

  • The operations (int) and >> on the variable v are redundant because the results are not used.

  • The operation = is redundant because the local variable x is not read after the operation.

  • The operation * on p++ is redundant because the result is not used.

The rule is not violated when:

  • A variable is cast to void. The cast indicates that you are intentionally not using the value.

  • The result of an operation is used. For instance, the operation * on p is not redundant, because *p is incremented.

Issue

This issue occurs on if-statements where the condition is always true. This defect occurs only on if-statements that do not have an else-statement.

This defect shows unnecessary if-statements when there is no difference in code execution if the if-statement is removed.

Risk

Unnecessary if statements often indicate a coding error. Perhaps the if condition is coded incorrectly or the if statement is not required at all.

Fix

The fix depends on the root cause of the defect. For instance, the root cause can be an error condition that is checked twice on the same execution path, making the second check redundant.

The fix depends on the root cause of the defect. Often the result details (or source code tooltips in Polyspace as You Code) show a sequence of events that led to the defect. You can implement the fix on any event in the sequence. If the result details do not show this event history, you can search for previous references of variables relevant to the defect using right-click options in the source code and find related events. See also Interpret Bug Finder Results in Polyspace Desktop User Interface or Interpret Bug Finder Results in Polyspace Access Web Interface (Polyspace Access).

See examples of fixes below.

If the redundant condition represents defensive coding practices and you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Example – if with Enumerated Type
typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card < 7) { //Noncompliant
        do_something(card);
    }
}

The type suit is enumerated with five options. However, the conditional expression card < 7 always evaluates to true because card can be at most 5. The if statement is unnecessary.

Correction 1 — Change Condition

One possible correction is to change the if-condition in the code. In this correction, the 7 is changed to UNKNOWN_SUIT to relate directly to the type of card.

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    if (card > UNKNOWN_SUIT) {
        do_something(card);
    }
}
Correction — Remove If

Another possible correction is to remove the if-condition in the code. Because the condition is always true, you can remove the condition to simplify your code.

typedef enum _suit {UNKNOWN_SUIT, SPADES, HEARTS, DIAMONDS, CLUBS} suit;
suit nextcard(void);
void do_something(suit s);

void bridge(void)
{
    suit card = nextcard();
    if ((card < SPADES) || (card > CLUBS)){
        card = UNKNOWN_SUIT;
    }

    do_something(card);
}
Issue

This issue occurs when a value assigned to a variable is never read.

For instance, you write a value to a variable and then write a second value before reading the previous value. The first write operation is redundant.

Risk

Redundant write operations often indicate programming errors. For instance, you forgot to read the variable between two successive write operations or unintentionally read a different variable.

Fix

Identify the reason why you write to the variable but do not read it later. Look for common programming errors such as accidentally reading a different variable with a similar name.

If you determine that the write operation is redundant, remove the operation.

Example – Write Without Further Read Error
void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor();             //Noncompliant
    /* Defect: Useless write */
}

After the variable level gets assigned the value 4 * getsensor(), it is not read.

Correction — Use Value After Assignment

One possible correction is to use the variable level after the assignment.

#include <stdio.h>

void sensor_amplification(void)
{
    extern int getsensor(void);
    int level;

    level = 4 * getsensor(); 
    
    /* Fix: Use level after assignment */
    printf("The value is %d", level);
    
}

The variable level is printed, reading the new value.

Check Information

Group: Rec. 48. Miscellaneous (MSC)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.