Unreachable code

Code cannot be reached during execution

Description

Unreachable code uses statement coverage to determine whether a section of code can be reached during execution. Statement coverage checks whether a program statement is executed. If a statement has test conditions, and at least one of them occurs, the statement is executed and reachable. The test conditions that do not occur are not considered dead code unless they have a corresponding code branch. If all the test conditions do not occur, the statement is not executed and each test condition is an instance of unreachable code. For example, in the switch statements of this code, case 3 never occurs:

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 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.

Other examples of unreachable code include:

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

  • If a test condition always evaluates to true, the condition is redundant. On the Source pane, the condition keyword, such as if, 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);	
}

Check Information

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