In programming and compiler theory, an unreachable code is a part of the program code that cannot be executed under any circumstances, since it is unattainable in the control flow graph [1] [2] .
Unreachable code is often referred to as one of the types of dead code , such terminology is usually used when considering the source code of programs [3] [4] . However, in the theory of compilers , these concepts are not connected in any way; dead code refers only to achievable code that does not affect program output [1] [2] [5] .
The main disadvantages of having an unreachable code in the program:
- It takes up excessive memory;
- It causes excessive caching of instructions in the CPU instruction cache - which also reduces data locality;
- It makes application support difficult - time and effort can be spent on supporting and documenting a piece of code that is unattainable, which means it never executes.
Reasons
The existence of an unreachable code may be due to various factors, for example:
- Software errors in complex conditional transitions ;
- Due to internal transformations performed by the optimizing compiler ;
- Incomplete testing of a new or modified program that failed to detect unreachable code;
- When correcting one error, the programmer created another error, which bypasses unreachable code and was not detected during testing;
- Outdated code that was not completely removed by the programmer because it was mixed with existing code;
- Outdated code that the programmer forgot to delete;
- Previously useful code that will never be executed, since, in the future, data entry will never lead to the execution of this code;
- Outdated code that was intentionally saved but made unreachable so that it can be included in the program again if necessary;
- Debug constructs and residual parts of the code that still need to be removed from the program.
In the last five cases, the unreachable code is inherited, that is, code that was once useful, but not used now.
Examples
Consider the following C example:
int foo ( int x , int y )
{
return x + y ;
int z = x * y ; / * Inaccessible code * /
}
The operation int z = x*y is an unreachable code, since it exits the procedure (the operations that stand after returning from the procedure may not be the unreachable code, for example, if the goto statement refers to the label after the return).
Analysis
The search for unreachable code in the source code can be performed using static code analysis [3] [4] . In the optimizing compiler , identifying and removing unreachable code can optimize the removal of unreachable code , which finds unreachable nodes in the control flow graph and deletes them [6] . A simple analysis of a CFG graph for unreachable nodes is often implemented in the compiler as a separate function, i.e. garbage collector , which is called immediately after the transformations that can change the graph of the control flow [7] .
The code may become unreachable as a result of performing other compiler transformations on the , for example, optimizing the removal of common subexpressions .
In practice, the complexity of the analysis implemented significantly affects the amount of unreachable code to be detected. For example, after folding constants and a simple analysis of the control flow, you may find that the code inside the if in the following example is unreachable:
int foo ( void )
{
int n = 2 + 1 ;
if ( n > 4 )
{
printf ( "% d" , n ); / * Inaccessible code * /
}
}
However, in order to identify unreachable code in the following example, it is necessary to apply a much more complex analysis algorithm:
int foo ( void )
{
double x = sqrt ( 2 );
if ( x > 4 )
{
printf ( "% lf" , x ); / * Inaccessible code * /
}
}
One practical solution is an approach that first performs a simple analysis of identifying unreachable code, and then uses a profiler to handle more complex cases. The profiler cannot prove that any part of the code is unreachable, but it can be a good heuristic for finding suspicious nodes that are probably unreachable. After finding these potentially unreachable nodes, you can apply some sort of powerful algorithm for analyzing unreachable code.
See also
- Dead code
- Dead Code Removal
- Removing Unreachable Code
Notes
- ↑ 1 2 Engineering a Compiler - S. 544.
- ↑ 1 2 Debray, SK, Evans, W., Muth, R., and De Sutter , B. 2000. Compiler techniques for code compaction . ACM Trans. Program. Lang. Syst. 22, 2 (Mar. 2000), 378-415. ( summary archived )
- ↑ 1 2 Dead code detection and removal . Aivosto. Date of treatment July 12, 2012. Archived on August 5, 2012.
- ↑ 1 2 Compares some free alternatives to DCD (Dead Code Detector) (link not available) . Java.net Date of treatment July 12, 2012. Archived September 23, 2012.
- ↑ Compilers - principles, technologies, tools - P. 669 ( unreachable code ), 713 ( dead code ).
- ↑ Engineering a Compiler - S. 550.
- ↑ A. Yu. Drozdov, A.M. Stepanenkov. Managed optimization packages. In Information Technology and Computing Systems , 2004, No. 3 ( text Archived )
Literature
- Cooper and Torczon. Engineering a Compiler. - Morgan Kaufmann, 2011 .-- S. 544-550, 593. - ISBN 978-0-12-088478-0 .
- Alfred Aho, Monica Lam, Ravi Seti, Jeffrey Ullman. Compilers: principles, technologies and tools = Compilers: Principles, Techniques, and Tools. - 2nd edition. - M .: "Williams", 2008. - 1184 p. - 1,500 copies - ISBN 978-5-8459-1349-4 .
- Muchnick, Steven S. Advanced Compiler Design and Implementation. - Morgan Kaufmann Publishers , 1997 .-- S. 580-582. - ISBN 1-55860-320-4 .