• Home   /  
  • Archive by category "1"

C5917 Removed Dead Assignment Sheet

Code that has no effect or is never executed (that is, dead or unreachable code) is typically the result of a coding error and can cause unexpected behavior. Such code is usually optimized out of a program during compilation. However, to improve readability and ensure that logic errors are resolved, it should be identified, understood, and eliminated.

Statements or expressions that have no effect should be identified and removed from code. Most modern compilers, in many cases, can warn about code that has no effect or is never executed. (See MSC00-C. Compile cleanly at high warning levels.) 

Noncompliant Code Example

This noncompliant code example demonstrates how dead code can be introduced into a program [Fortify 2006]. The second conditional statement, , will never evaluate true because it requires that not be assigned , and the only path where can be assigned a non-null value ends with a statement.

Compliant Solution

Remediation of dead code requires the programmer to determine why the code is never executed and then to resolve the situation appropriately. To correct the preceding noncompliant code, the is removed from the body of the first conditional statement.

Noncompliant Code Example

In this example, the function is used to limit the number of times the function will iterate. The conditional statement inside the loop evaluates to true when the current character in the string is the null terminator. However, because returns the number of characters that precede the null terminator, the conditional statement never evaluates true.

Compliant Solution

Removing the dead code depends on the intent of the programmer. Assuming the intent is to flag and process the last character before the null terminator, the conditional is adjusted to correctly determine if the refers to the index of the last character before the null terminator.

Noncompliant Code Example (Assignment)

In this noncompliant code example, the comparison of to has no effect:

This code is likely a case of the programmer mistakenly using the equals operator instead of the assignment operator .

Compliant Solution (Assignment)

The assignment of to is now properly performed:

Noncompliant Code Example (Dereference)

In this example, a pointer increment and then a dereference occur, but the dereference has no effect:

Compliant Solution (Dereference)

Correcting this example depends on the intent of the programmer. For example, if dereferencing was a mistake, then should not be dereferenced.

If the intent was to increment the value referred to by , then parentheses can be used to ensure is dereferenced and then incremented. (See EXP00-C. Use parentheses for precedence of operation.)

Another possibility is that is being used to reference a memory-mapped device. In this case, the variable should be declared as .

Noncompliant Code Example (if/else if)

A chain of if/else if statements is evaluated from top to bottom. At most, only one branch of the chain will be executed: the first one with a condition that evaluates to true. Consequently, duplicating a condition in a sequence of if/else if statements automatically leads to dead code.

Compliant Solution (if/else if)

In this compliant solution, the third conditional expression has been corrected.

Noncompliant Code Example (logical operators)

Using the same subexpression on either side of a logical operator is almost always a mistake.  In this noncompliant code example, the rightmost subexpression of the controlling expression of each statement has no effect.  

Compliant Solution (logical operators)

In this compliant solution, the rightmost subexpression of the controlling expression of each statement has been removed.

Noncompliant Code Example (Unconditional Jump)

Unconditional jump statements typically has no effect.  

Compliant Solution (Unconditional Jump)

The continue statement has been removed from this compliant solution.

Exceptions

MSC07-C-EX1: In some situations, seemingly dead code may make software resilient. An example is the label in a statement whose controlling expression has an enumerated type and that specifies labels for all enumerations of the type. (See MSC01-C. Strive for logical completeness.) Because valid values of an enumerated type include all those of its underlying integer type, unless enumeration constants are provided for all those values, the label is appropriate and necessary.

MSC07-C-EX2: It is permissible to temporarily remove code that may be needed later. (See MSC04-C. Use comments consistently and in a readable fashion for an illustration.)

Risk Assessment

The presence of code that has no effect or is never executed can indicate logic errors that may result in unexpected behavior and vulnerabilities. Such code can be introduced into programs in a variety of ways and eliminating it can require significant analysis.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

MSC12-C

Low

Unlikely

Medium

P2

L3

Automated Detection

Tool

Version

Checker

Description

Astrée17.04i

unreachable-code

statement-sideeffect

Partially checked
CodeSonar4.5p1

DIAG.UNEX.*
LANG.STRUCT.EBS
LANG.STRUCT.RC
MISC.NOEFFECT
LANG.STRUCT.UC
LANG.STRUCT.UA
LANG.STRUCT.UULABEL

LANG.STRUCT.UUMACRO
LANG.STRUCT.UUPARAM
LANG.STRUCT.UUTAG
LANG.STRUCT.UUTYPE
LANG.STRUCT.UUVAR

Code not exercised by analysis
Empty branch statement checks
Redundant condition
Function call has no effect
Unreachable code checks
Useless assignment
Unused Label
Unused Macro
Unused Parameter
Unused Tag
Unused Type
Unused Variable

Coverity

2017.07

NO_EFFECT

DEADCODE

UNREACHABLE

Finds statements or expressions that do not accomplish anything or statements that perform an unintended action.

Can detect the specific instance where code can never be reached because of a logical contradiction or a dead "default" in statement

Can detect the instances where code block is unreachable because of the syntactic structure of the code

ECLAIR

1.2

CC2.MSC12

Partially implemented

GCC

3.0


Options detect unused local variables, nonconstant static variables and unused function parameters, or unreachable code respectively.

Klocwork2017

CWARN.NOEFFECT.SELF_ASSIGN
CWARN.NOEFFECT.UCMP.GE
CWARN.NOEFFECT.UCMP.GE.MACRO
CWARN.NOEFFECT.UCMP.LT
CWARN.NOEFFECT.UCMP.LT.MACRO
CWARN.NULLCHECK.FUNCNAME
EFFECT
INVARIANT_CONDITION.UNREACH
LA_UNUSED
MISRA.STMT.NO_EFFECT
UNREACH.GEN
UNREACH.RETURN
UNREACH.SIZEOF
VA_UNUSED.GEN
VA_UNUSED.INIT

LDRA tool suite9.7.18 D, 65 D, 105 D, I J, 139 S, 140 S, 57 S

Partially implemented

Parasoft C/C++test 10.3 MISRA2008-0_1_{a,b,c,d,e,f,g}, BD-PB-SWITCH
Polyspace Bug FinderR2016a

Dead code

Unreachable code

Use of memset with size argument zero

Code does not execute

Default case is missing and may be reached

Size argument of function in  family is zero

PRQA QA-C9.3

3426, 3427, 3307, 3110, 3112, 3404, 1501, 1503, 2008, 2880, 2881, 2882, 2883, 2877, 3196, 3202, 3203, 3205, 3206, 3207, 3210, 3219, 3229, 3404, 3422, 3423, 3425, 3470, 2980, 2981, 2982, 2983, 2984, 2985, 2986

Partially implemented
RuleChecker17.04i

statement-sideeffect

Partially checked
SonarQube C/C++ Plugin3.11S1764, S2589, S2583, S1116, S1172, S1763, S1862, S1065, S1656, S2754, S1751
Splint3.1.1

The default mode checks for unreachable code.

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

CVE-2014-1266 results from a violation of this rule. There is a spurious statement on line 631 of sslKeyExchange.c. This  statement gets executed unconditionally, even though it is indented as if it were part of the preceding statement. As a result, the call to  (which would perform the actual signature verification) becomes dead code [ImperialViolet 2014].

Related Guidelines

Bibliography


int func(int condition) { char *s = NULL; if (condition) { s = (char *)malloc(10); if (s == NULL) { /* Handle Error */ } /* Process s */ return 0; } /* ... */ if (s) { /* This code is unreachable */ } return 0; }
int func(int condition) { char *s = NULL; if (condition) { s = (char *)malloc(10); if (s == NULL) { /* Handle error */ } /* Process s */ } /* ... */ if (s) { /* This code is now reachable */ } return 0; }
int s_loop(char *s) { size_t i; size_t len = strlen(s); for (i=0; i < len; i++) { /* ... */ if (s[i] == '\0') { /* This code is never reached */ } } return 0; }
int s_loop(char *s) { size_t i; size_t len = strlen(s); for (i=0; i < len; i++) { /* ... */ if (s[i+1] == '\0') { /* This code is now reached */ } } return 0; }
int a; int b; /* ... */ a == b;
int a; int b; /* ... */ a = b;
int *p; /* ... */ (*p)++;
volatile int *p; /* ... */ (void) *(p++);
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 1) /* Duplicated condition */ moveWindowToTheBackground();
if (param == 1) openWindow(); else if (param == 2) closeWindow(); else if (param == 3) moveWindowToTheBackground();
if (a == b && a == b) { // if the first one is true, the second one is too do_x(); } if (a == c || a == c ) { // if the first one is true, the second one is too do_w(); }
if (a == b) { do_x(); } if (a == c) { do_w(); }
#include <stdio.h>   for (int i = 0; i < 10; ++i) { printf("i is %d", i); continue; // this is meaningless; the loop would continue anyway }
#include <stdio.h>   for (int i = 0; i < 10; ++i) { printf("i is %d", i); }
typedef enum { Red, Green, Blue } Color; const char* f(Color c) { switch (c) { case Red: return "Red"; case Green: return "Green"; case Blue: return "Blue"; default: return "Unknown color"; /* Not dead code */ } } void g() { Color unknown = (Color)123; puts(f(unknown)); }

In compiler theory, dead code elimination (also known as DCE, dead code removal, dead code stripping, or dead code strip) is a compiler optimization to remove code which does not affect the program results. Removing such code has several benefits: it shrinks program size, an important consideration in some contexts, and it allows the running program to avoid executing irrelevant operations, which reduces its running time. It can also enable further optimizations by simplifying program structure. Dead code includes code that can never be executed (unreachable code), and code that only affects dead variables (written to, but never read again), that is, irrelevant to the program.

Examples[edit]

Consider the following example written in C.

intfoo(void){inta=24;intb=25;/* Assignment to dead variable */intc;c=a*4;returnc;b=24;/* Unreachable code */return0;}

Simple analysis of the uses of values would show that the value of after the first assignment is not used inside . Furthermore, is declared as a local variable inside , so its value cannot be used outside . Thus, the variable is dead and an optimizer can reclaim its storage space and eliminate its initialization.

Furthermore, because the first return statement is executed unconditionally, no feasible execution path reaches the second assignment to . Thus, the assignment is unreachable and can be removed. If the procedure had a more complex control flow, such as a label after the return statement and a elsewhere in the procedure, then a feasible execution path might exist to the assignment to .

Also, even though some calculations are performed in the function, their values are not stored in locations accessible outside the scope of this function. Furthermore, given the function returns a static value (96), it may be simplified to the value it returns (this simplification is called constant folding).

Most advanced compilers have options to activate dead code elimination, sometimes at varying levels. A lower level might only remove instructions that cannot be executed. A higher level might also not reserve space for unused variables. Yet a higher level might determine instructions or functions that serve no purpose and eliminate them.

A common use of dead code elimination is as an alternative to optional code inclusion via a preprocessor. Consider the following code.

intmain(void){inta=5;intb=6;intc;c=a*(b/2);if(0){/* DEBUG */printf("%d\n",c);}returnc;}

Because the expression 0 will always evaluate to false, the code inside the if statement can never be executed, and dead code elimination would remove it entirely from the optimized program. This technique is common in debugging to optionally activate blocks of code; using an optimizer with dead code elimination eliminates the need for using a preprocessor to perform the same task.

In practice, much of the dead code that an optimizer finds is created by other transformations in the optimizer. For example, the classic techniques for operator strength reduction insert new computations into the code and render the older, more expensive computations dead.[1] Subsequent dead code elimination removes those calculations and completes the effect (without complicating the strength-reduction algorithm).

Historically, dead code elimination was performed using information derived from data-flow analysis.[2] An algorithm based on static single assignment form (SSA) appears in the original journal article on SSA form by Ron Cytron et al.[3] Robert Shillingsburg (aka Shillner) improved on the algorithm and developed a companion algorithm for removing useless control-flow operations.[4]

Dynamic dead code elimination[edit]

Dead code is normally considered dead unconditionally. Therefore, it is reasonable attempting to remove dead code through dead code elimination at compile time.

However, in practice it is also common for code sections to represent dead or unreachable code only under certain conditions, which may not be known at the time of compilation or assembly. Such conditions may be imposed by different runtime environments (for example different versions of an operating system, or different sets and combinations of drivers or services loaded in a particular target environment), which may require different sets of special cases in the code, but at the same time become conditionally dead code for the other cases.[5] Also, the software (for example, a driver or resident service) may be configurable to include or exclude certain features depending on user preferences, rendering unused code portions useless in a particular scenario.[5] While modular software may be developed to dynamically load libraries on demand only, in most cases, it is not possible to load only the relevant routines from a particular library, and even if this would be supported, a routine may still include code sections which can be considered dead code in a given scenario, but could not be ruled out at compile time, already.

The techniques used to dynamically detect demand, identify and resolve dependencies, remove such conditionally dead code, and to recombine the remaining code at load or runtime are called dynamic dead code elimination[5][6][7][8][9][10][11][12] or dynamic dead instruction elimination.[13]

Most programming languages, compilers and operating systems offer no or little more support than dynamic loading of libraries and late linking, therefore software utilizing dynamic dead code elimination is very rare with languages compiled ahead-of-time or written in assembly language.[6][9] However, language implementations doing just-in-time compilation may dynamically optimize for dead code elimination.[12][14][15]

Although with a rather different focus, similar approaches are sometimes also utilized for dynamic software updating and hot patching.

See also[edit]

References[edit]

Further reading[edit]

  • Bodík, Rastislav; Gupta, Rajiv (June 1997). Partial dead code elimination using slicing transformations. Proceedings of the ACMSIGPLAN 1997 conference on Programming language design and implementation (PLDI '97). pp. 682–694. 
  • Aho, Alfred Vaino; Sethi, Ravi; Ullman, Jeffrey David (1986). Compilers - Principles, Techniques and Tools. Addison Wesley Publishing Company. ISBN 0-201-10194-7. 
  • Muchnick, Steven Stanley (1997). Advanced Compiler Design and Implementation. Morgan Kaufmann Publishers. ISBN 1-55860-320-4. 
  • Grune, Dick; Bal, Henri Elle; Jacobs, Ceriel J. H.; Langendoen, Koen G. (2000). Modern Compiler Design. John Wiley & Sons, Inc.ISBN 0-471-97697-0. 

External links[edit]

  1. ^Allen, Frances; Cocke, John; Kennedy, Ken (June 1981). "Reduction of Operator Strength". In Jones, Neil D.; Muchnick, Steven Stanley. Program Flow Analysis: Theory & Application. Prentice-Hall. ISBN 0137296819. 
  2. ^Kennedy, Ken (June 1981). "A Survey of Data-flow Analysis Techniques". In Jones, Neil D.; Muchnick, Steven Stanley. Program Flow Analysis: Theory & Application. Prentice-Hall. ISBN 0137296819. 
  3. ^Cytron, Ron K.; Ferrante, Jeanne; Rosen, Barry K.; Zadeck, F. Kenneth (1991). Efficiently Computing Static Single Assignment Form and the Program Dependence Graph. ACMTOPLAS 13(4). 
  4. ^Cooper, Keith D.; Torczon, Linda (2003) [2002-01-01]. Engineering a Compiler. Morgan Kaufmann. pp. 498ff. ISBN 978-1558606982. 
  5. ^ abcPaul, Matthias (2002-04-03). "[fd-dev] Ctrl+Alt+Del". Archived from the original on 2017-09-09. Retrieved 2017-09-09.  
  6. ^ abPaul, Matthias; Frinke, Axel C. (1997-10-13) [first published 1991], FreeKEYB - Enhanced DOS keyboard and console driver (User Manual) (v6.5 ed.)  (NB. FreeKEYB is a Unicode-based dynamically configurable successor of K3PLUS supporting most keyboard layouts, code pages, and country codes. Utilizing an off-the-shelf macro assembler as well as a framework of automatic pre- and post-processing analysis tools to generate dependency and code morphingmeta data to be embedded into the executable file alongside the binary code and a self-discarding, relaxing and relocating loader, the driver implements byte-level granular dynamic dead code elimination and relocation techniques at load-time as well as self-modifying code and reconfigurability at run-time to minimize its memory footprint downto close the canonical form depending on the underlying hardware, operating system, and driver configuration as well as the selected feature set and locale (about sixty configuration switches with hundreds of options for an almost unlimited number of possible combinations). This complexity and the dynamics are hidden from users, who deal with a single executable file just like they would do with a conventional driver. K3PLUS was an extended keyboard driver for DOS widely distributed in Germany at its time, with adaptations to a handful of other European languages available. It supported a sub-set of features already, but did not implement dynamic dead code eliminiation.)
  7. ^Paul, Matthias (2001-04-10). "[ANN] FreeDOS beta 6 released". de.comp.os.msdos (in German). Archived from the original on 2017-09-09. Retrieved 2017-07-02. 
  8. ^Paul, Matthias (2001-12-30). "KEYBOARD.SYS internal structure". comp.os.msdos.programmer. Archived from the original on 2017-09-09. Retrieved 2017-07-03.  
  9. ^ abPaul, Matthias; Frinke, Axel C. (2006-01-16), FreeKEYB - Advanced international DOS keyboard and console driver (User Manual) (v7 preliminary ed.) 
  10. ^Paul, Matthias (2002-02-02). "Treiber dynamisch nachladen (Intra-Segment-Offset-Relokation zum Laden von TSRs in die HMA)" [Loading drivers dynamically (Intra-segment offset relocation to load TSRs into the HMA)]. de.comp.os.msdos (in German). Archived from the original on 2017-09-09. Retrieved 2017-07-02. 
  11. ^Glew, Andy (2011-03-02). "Dynamic dead code elimination and hardware futures". [1][2]
  12. ^ abConway, Andrew (1995-12-04). "Cyclic data structures". comp.lang.functional. Archived from the original on 2017-09-09. Retrieved 2017-07-03.   (NB. Possibly the first public use of the term dynamic dead code elimination, though only conceptually and with a focus on lazy evaluation in functional languages.)
  13. ^Butts, J. Adam; Sohi, Guri (October 2002). "Dynamic Dead-Instruction Detection and Elimination"(PDF). San Jose, CA, USA: Computer Science Department, University of Wisconsin-Madison. ASPLOS X ACM 1-58113-574-2/02/0010. Retrieved 2017-06-23. 
  14. ^Johng, Yessong; Danielsson, Per; Ehnsiö, Per; Hermansson, Mats; Jolanki, Mika; Moore, Scott; Strander, Lars; Wettergren, Lars (2002). "Chapter 5. Java overview and iSeries implementation - 5.1.1. Miscellaneous components". Intentia Movex Java on the IBM iSeries Server - An Implementation Guide - Overview of Movex Java on the iSeries server - Movex Java on iSeries installation and configuration - Operational tips and techniques. Red Books. IBM Corp. p. 41. ISBN 0738424617. SG24-6545-00. Retrieved 2017-06-23. 
  15. ^Polito, Guillermo (2015). "Virtualization Support for Application Runtime Specialization and Extension - Programming Languages"(PDF). Universite des Sciences et Technologies de Lille. pp. 111–124. HAL Id: tel-01251173. Archived(PDF) from the original on 2017-06-23. Retrieved 2017-06-23. 

One thought on “C5917 Removed Dead Assignment Sheet

Leave a comment

L'indirizzo email non verrà pubblicato. I campi obbligatori sono contrassegnati *