Main Content

Unreachable code

Code cannot be reached during execution

Description

This check determines whether a section of code is statically unreachable. To determine reachability, the check evaluates conditions that decide if a section of code is executed.

  • If at least one of the conditions statically evaluates to true, the section of code is considered reachable.

  • If all the conditions always evaluate to false, the section of code appears as unreachable code.

  • The conditions that are not evaluated at all or that always evaluate to true also appear as unreachable code.

Examples of unreachable code include the following:

  • If an if condition expression always evaluates to false, the corresponding code branch cannot be reached. On the Source pane, the opening brace of the branch is gray.

  • If an if condition expression always evaluates to true, the condition is redundant. On the Source pane, the if keyword appears gray.

  • The code follows a break or return statement.

If an opening brace of a code block appears gray on the Source pane, to highlight the entire block, double-click the brace.

The check operates on code inside a function. The checks Function not called and Function not reachable determine if the function itself is not called or called from unreachable code.

Examples

expand all

#define True 1
#define False 0
 
typedef enum {
  Intermediate, End, Wait, Init
} enumState;
 
enumState input();
enumState inputRef();
void operation(enumState, int);
  
int checkInit (enumState stateval)  {
  if (stateval == Init) 
    return True;
  return False;
}
 
int checkWait (enumState stateval)  {
  if (stateval == Wait) 
    return True;
  return False;
}
  
void main()  {
  enumState myState = input(),refState = inputRef() ;
  if(checkInit(myState)){
    if(checkWait(myState)) {
      operation(myState,checkInit(refState));	
    } else {
      operation(myState,checkWait(refState));
    }
  }
} 

In this example, the main enters the branch of if(checkInit(myState)) only if myState = Init. Therefore, inside that branch, Polyspace® considers that myState has value Init. checkWait(myState) always returns False and the first branch of if(checkWait(myState)) is unreachable.

Correction — Remove Redundant Test

One possible correction is to remove the redundant test if(checkWait(myState)).

#define True 1
#define False 0
 
typedef enum {
  Intermediate, End, Wait, Init
} enumState;
 
enumState input();
enumState inputRef();
void operation(enumState, int);

int checkInit (enumState stateval)  {
  if (stateval == Init) 
    return True;
  return False;
}
 
int checkWait (enumState stateval)  {
  if (stateval == Wait) return True;
  return False;
}
   
void main()  {
  enumState myState = input(),refState = inputRef() ;
  if(checkInit(myState))
    operation(myState,checkWait(refState));
} 
#include <stdlib.h>
#include <time.h>

int roll() {
  return(rand()%6+1);
}

void operation(int);
     
void main()   {
    srand(time(NULL));
    int die = roll();
    if(die >= 1 && die <= 6)
      /*Unreachable code*/
      operation(die);
  }

In this example, roll() returns a value between 1 and 6. Therefore the if test in main always evaluates to true and is redundant. If there is a corresponding else branch, the gray error appears on the else statement. Without an else branch, the gray error appears on the if keyword to indicate the redundant condition.

Correction — Remove Redundant Test

One possible correction is to remove the condition if(die >= 1 && die <=6).

#include <stdlib.h>
#include <time.h>

int roll() {
  return(rand()%6+1);
}

void operation(int);
     
void main()   {
  srand(time(NULL));
  int die = roll();
  operation(die);
}
#include <stdlib.h>
#include <time.h>
#define True 1
#define False 0

int roll1() {
  return(rand()%6+1);
}

int roll2();
void operation(int,int);
    
void main()   {
  srand(time(NULL));
  int die1 = roll1(),die2=roll2();
  if((die1>=1 && die1<=6) || 
     (die2>=1 && die2 <=6))
  /*Unreachable code*/
    operation(die1,die2);
}

In this example, roll1() returns a value between 1 and 6. Therefore, the first part of the if test, if((die1>=1) && (die1<=6)) is always true. Because the two parts of the if test are combined with ||, the if test is always true irrespective of the second part. Therefore, the second part of the if test is unreachable.

Correction — Combine Tests with &&

One possible correction is to combine the two parts of the if test with && instead of ||.

#include <stdlib.h>
#include <time.h>
#define True 1
#define False 0

int roll1() {
  return(rand()%6+1);
}

int roll2();
void operation(int,int);
    
void main()   {
  srand(time(NULL));
  int die1 = roll1(),die2=roll2();
  if((die1>=1 && die1<=6) && 
     (die2>=1 && die2<=6))
    operation(die1,die2);	
}
typedef enum {init, run, completion} states;

int getAnInput();

states a = init;

void f(int b)
{
    switch (a) {
    case init: {
        if (b == 3) {
            a = completion;
        }
        break;
    }
    case completion: {
        if (b == 1) {      //Unreachable code
            //....
        }
        break;
    }
        //...
    }
}

void main()
{
    int b = getAnInput();
    f(b);
    f(b);
}

Sometimes, a block can be unreachable because variable values are constrained by prior operations in the code. If you do not understand why a condition is always true or false, see if variables in the condition are constrained because of some prior operation.

In this example, the function getAnInput() is stubbed since its definition is not given. The variable b, which is initialized through getAnInput(), can take any value allowed by the int data type. It may seem that in the calls to f(), b can have any value including the values 1 and 3. However, the condition (b == 1) appears false and the corresponding block unreachable.

Examine the two calls to f(). In the first call to f(), the switch statement selects case init. Within case init, b can be full range. If b is equal to 3, a is set to completion. The second time function f() is called, the switch statement can select either case init or case completion. Because the only way case completion can be selected is when b was previously equal to 3, and because there is no manipulation of b outside of case init, Polyspace assumes b is still equal to 3. Thus, the if statement condition (b == 1) can never be met resulting in unreachable code within case completion.

void test1 (int a)
{
    int tmp = 0;
    if ((a!=3))
        {
            switch (a)
                {
                case 1:
                    tmp++;
                    break;
                default:
                    tmp = 1;
                    break;
                /* case 3 falls through to
                   case 2, no dead code */
                case 3:
                case 2:
                    tmp = 100;
                    break;
                }
        }
}

void test2 (int a)
{
    int tmp = 0;
    if ((a!=3))
        {
            switch (a)
                {
                case 1:
                    tmp++;
                    break;
                default:
                    tmp = 1;
                    break;
// Dead code on case 3
                case 3:
                    break;
                case 2:
                    tmp = 100;
                    break;
                }
        }
}

In this example, case 3 of the switch statement is unreachable in both functions test1() and test2().

  • In test1(), case 3 falls through to case 2 and the check shows no dead code.

  • In test2(), the check shows dead code for case 3 because the break statement on the next line is not executed.

Check Information

Group: Data flow
Language: C | C++
Acronym: UNR

Version History

expand all