Main Content

Review and Fix Unreachable Code Checks

This topic describes how to systematically review the results of an Unreachable code check in Polyspace® Code Prover™.

Follow one or more of these steps until you determine a fix for the Unreachable code check. There are multiple ways to fix this check. For a description of the check and code examples, see Unreachable code.

If you determine that the check represents defensive code, add a comment and justification in your result or code explaining why you did not change your code. See Address Results in Polyspace User Interface Through Bug Fixes or Justifications or Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access).

Step 1: Interpret Check Information

  1. Select the check on the Results List or Source pane.

  2. View the message on the Result Details pane and the corresponding unreachable code on the Source pane.

    • The message on the Result Details pane explains why the block of code is unreachable.

      Example unreachable code message

    • The Source pane shows the unreachable code highlighted in gray.

      Depending on the kind of unreachable code, a keyword or a code block might be highlighted in gray. For instance, if an if condition expression always evaluates to true, the if keyword appears highlighted. If the condition expression always evaluates to false, the corresponding code block that is unreachable appears highlighted.

  3. A code block is usually unreachable when the condition that determines entry into the block is not satisfied. See why the condition is not satisfied.

    1. On the Source pane, place your cursor on the variables involved in the condition to determine their values.

    2. Using these values, see why the condition is not satisfied.

    Note

    Sometimes, a condition itself is redundant. For example, it is always true or coupled:

    • Through an || operator to another condition that is always true.

    • Through an && operator to another condition that is always false.

    For example, in the following code, the condition x%2==0 is redundant because the first condition x>0 is always true.

    assert(x>0);
    if(x>0 || x%2 == 0)
    If a condition is redundant, instead of a block of code, the condition itself is marked gray.

Step 2: Determine Root Cause of Check

Trace the data flow for each variable involved in the condition.

In the following example, trace the data flow for arg.

void foo(void) {
    int x=0;
    .
    .
    bar(x);
    .
    .
}

void bar(int arg) {
    if(arg==0) {
        /*Block 1*/
    }
    else {
        /*Block 2*/
    }
}
You might find that bar is called only from foo. Since the only argument of bar has value 0, the else branch of if(arg==0) is unreachable.

Possible fix: If you do not intend to call bar elsewhere and know that the values passed to bar will not change, you can remove the if-else statement in bar and retain only the content of Block 1.

To trace the data flow, select the check and note the information on the Result Details pane.

  • If the Result Details pane shows the sequence of instructions that lead to the check, select each instruction.

  • If the Result Details pane shows the line number of probable cause for the check, right-click the Source pane. Select Go To Line.

  • Otherwise, for each variable involved in the condition, find previous instances and trace back to the root cause of check. For more information on common root causes, see Step 3: Look for Common Causes of Check.

    Depending on the variable, use the following navigation shortcuts to find previous instances. You can perform the following steps in the Polyspace user interface only.

    VariableHow to Find Previous Instances of Variable

    Local Variable

    Use one of the following methods:

    • Search for the variable.

      1. Right-click the variable. Select Search For All References.

        All instances of the variable appear on the Search pane with the current instance highlighted.

      2. On the Search pane, select the previous instances.

    • Browse the source code.

      1. Double-click the variable on the Source pane.

        All instances of the variable are highlighted.

      2. Scroll up to find the previous instances.

    Global Variable

    Right-click the variable. If the option Show In Variable Access View appears, the variable is a global variable.

    1. Select the option Show In Variable Access View.

      On the Variable Access pane, the current instance of the variable is shown.

    2. On this pane, select the previous instances of the variable.

      Write operations on the variable are indicated with write opterations arrow icon and read operations with read operations arrow icon.

    Function return value

    ret=func();

    1. Find the function definition.

      Right-click func on the Source pane. Select Go To Definition, if the option exists. If the definition is not available to Polyspace, selecting the option takes you to the function declaration.

    2. In the definition of func, identify each return statement. The variable that the function returns is your new variable to trace back.

    You can also determine if variables in any operation are related from some previous operation. See Find Relations Between Variables in Code.

Step 3: Look for Common Causes of Check

Look for common causes of the Unreachable code check.

  • Look for the following in your if tests:

    • You are testing the variables that you intend to test.

      For example, you might have a local variable that shadows a global variable. You might be testing the local variable when you intend to test the global one.

    • You are using parentheses to impose the sequence in which you want operations in the if test to execute.

      For example, if((!a && b) || c) imposes a different sequence of operations from if(!(a && b) || c). Unless you use parentheses, the operations obey operator precedence rules. The rules can cause the operations to execute in a sequence that you did not intend.

    • You are using = and == operators in the right places.

    Possible fix: Correct errors if any.

  • See if you are performing a test that you have performed previously.

    The redundant test typically occurs on the argument of a function. The same test is performed both in the calling and called function.

    void foo(void) {
        if(x>0)
            bar(x);
        .
        .
    }
    
    void bar(int arg) {
        if(arg==0) {
        }
    }

    Possible fix: If you intend to call bar later, for example, in yet unwritten code, or reuse bar in other programs, retain the test in bar. Otherwise, remove the test.

  • See if your code is unreachable because it follows a break or return statement.

    Possible fix: See if you placed the break or return statement at an unintended place.

  • See if the section of unreachable code exists because you are following a coding standard. If so, retain the section.

    For example, the default block of a switch-case statement is present to capture abnormal values of the switch variable. If such values do not occur, the block is unreachable. However, you might violate a coding standard if you remove the block.

  • See if the unreachable code is related to an orange check earlier in the code. Following an orange check, Polyspace normally terminates execution paths that contain an error. Because of this termination, code following an orange check can appear gray.

    For example, Polyspace places an orange check on the dereference of a pointer ptr if you have not vetted ptr for NULL. However, following the dereference, it considers that ptr is not NULL. If a test if(ptr==NULL) follows the dereference of ptr, Polyspace marks the corresponding code block unreachable.

    For more examples, see:

    Possible fix: Investigate the orange check. In the above example, investigate why the test if(ptr==NULL) occurs after the dereference and not before.