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
Select the check on the Results List or Source pane.
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.
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, theif
keyword appears highlighted. If the condition expression always evaluates to false, the corresponding code block that is unreachable appears highlighted.
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.
On the Source pane, place your cursor on the variables involved in the condition to determine their values.
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 conditionx>0
is always true.If a condition is redundant, instead of a block of code, the condition itself is marked gray.assert(x>0); if(x>0 || x%2 == 0)
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*/
}
}
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.
Variable How to Find Previous Instances of Variable Local Variable
Use one of the following methods:
Search for the variable.
Right-click the variable. Select Search For All References.
All instances of the variable appear on the Search pane with the current instance highlighted.
On the Search pane, select the previous instances.
Browse the source code.
Double-click the variable on the Source pane.
All instances of the variable are highlighted.
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.
Select the option Show In Variable Access View.
On the Variable Access pane, the current instance of the variable is shown.
On this pane, select the previous instances of the variable.
Write operations on the variable are indicated with and read operations with .
Function return value
ret=func();
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.In the definition of
func
, identify eachreturn
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 fromif(!(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.
Use Polyspace Bug Finder™ to check for common defects such as
Invalid use of = operator
andVariable shadowing
.To avoid errors due to incorrect operation sequence, check for violations of
MISRA C:2012 Rule 12.1
.
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 reusebar
in other programs, retain the test inbar
. Otherwise, remove the test.See if your code is unreachable because it follows a
break
orreturn
statement.Possible fix: See if you placed the
break
orreturn
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 aswitch-case
statement is present to capture abnormal values of theswitch
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 vettedptr
forNULL
. However, following the dereference, it considers thatptr
is notNULL
. If a testif(ptr==NULL)
follows the dereference ofptr
, Polyspace marks the corresponding code block unreachable.For more examples, see:
Gray Check Following Orange Check
An exception to this behavior is overflow. If you specify the appropriate Overflow mode for signed integer or Overflow mode for unsigned integer, Polyspace wraps the result of an overflow and does not terminate the execution paths. See
Overflow mode for signed integer (-signed-integer-overflows)
orOverflow mode for unsigned integer (-unsigned-integer-overflows)
.
Possible fix: Investigate the orange check. In the above example, investigate why the test
if(ptr==NULL)
occurs after the dereference and not before.