After a failure has been detected, it is necessary to first identify the program statement(s) that are in error and are responsible for the failure, the error can then be fixed.
The following are some of the approaches that are popularly adopted by the programmers for debugging:
Brute force method
This is the most common method of debugging but is the least efficient method.
In this approach, print statements are inserted throughout the program to print the intermediate values with the hope that some of the printed values will help to identify the statement in error.
This approach becomes more systematic with the use of a symbolic debugger (also called a source code debugger ), because values of different variables can be easily checked and break points and watch points can be easily set to test the values of variables effortlessly.
Single stepping using a symbolic debugger is another form of this approach, where the developer mentally computes the expected result after every source instruction and checks whether the same is computed by single stepping through the program.
This is also a fairly common approach.
In this approach, starting from the statement at which an error symptom has been observed, the source code is traced backwards until the error is discovered.
Unfortunately, as the number of source lines to be traced back increases, the number of potential backward paths increases and may become unmanageably large for complex programs, limiting the use of this approach.
Cause elimination method
In this approach, once a failure is observed, the symptoms of the failure (i.e., certain variable is having a negative value though it should be positive, etc.) are noted.
Based on the failure symptoms, the causes which could possibly have contributed to the symptom is developed and tests are conducted to eliminate each.
A related technique of identification of the error from the error symptom is the software fault tree analysis.
This technique is similar to back tracking.
In the backtracking approach, one often has to examine a large number of statements. However, the search space is reduced by defining slices.
A slice of a program for a particular variable and at a particular statement is the set of source lines preceding this statement that can influence the value of that variable.
Program slicing makes use of the fact that an error in the value of a variable can be caused by the statements on which it is data dependent.
Debugging is often carried out by programmers based on their ingenuity and experience.
The following are some general guidelines for effective debugging:
- Many times debugging requires a thorough understanding of the program design. Trying to debug based on a partial understanding of the program design may require an inordinate amount of effort to be put into debugging even for simple problems.
- Debugging may sometimes even require full redesign of the system. In such cases, a common mistakes that novice programmers often make is attempting not to fix the error but its symptoms.
- One must be beware of the possibility that an error correction may introduce new errors. Therefore after every round of error-fixing, regression testing must be carried out.
PROGRAM ANALYSIS TOOLS
A program analysis tool usually is an automated tool that takes either the source code or the executable code of a program as input and produces reports regarding several important characteristics of the program, such as its size, complexity, adequacy of commenting, adherence to programming standards, adequacy of testing, etc.
Types of program analysis tools
We can classify various program analysis tools into the following two broad categories:
- Static analysis tools
- Dynamic analysis tools
Static Analysis Tools
Static program analysis tools assess and compute various characteristics of a program without executing it.
Typically, static analysis tools analyse the source code to compute certain metrics characterising the source code (such as size, cyclomatic complexity, etc.) and also report certain analytical conclusions.
These also check the conformance of the code with the prescribed coding standards.
In this context, it displays the following analysis results:
- To what extent the coding standards have been adhered to?
- Whether certain programming errors such as uninitialised variables, mismatch between actual and formal parameters, variables that are declared but never used, etc., exist? A list of all such errors is displayed.
A major practical limitation of the static analysis tools lies in their inability to analyse run-time information such as dynamic memory references using pointer variables and pointer arithmetic, etc.
In a high level programming languages, pointer variables and dynamic memory allocation provide the capability for dynamic memory references.
Dynamic Analysis Tools
Dynamic program analysis tools can be used to evaluate several program
characteristics based on an analysis of the run time behaviour of a program.
These tools usually record and analyse the actual behaviour of a program while it is being executed.
A dynamic program analysis tool (also called a dynamic analyser ) usually collects execution trace information by instrumenting the code.
Code instrumentation is usually achieved by inserting additional statements to print the values of certain variables into a file to collect the execution trace of the program.
The instrumented code, when executed, records the behaviour of the software for different test cases.
An important characteristic of a test suite that is computed by a dynamic analysis tool is the extent of coverage achieved by the test suite.
After a software has been tested with its full test suite and its behaviour recorded, the dynamic analysis tool carries out a post execution analysis and produces reports which describe the coverage that has been achieved by the complete test suite for the program.
For example, the dynamic analysis tool can report the statement, branch, and path coverage achieved by a test suite.
If the coverage achieved is not satisfactory more test cases can be designed, added to the test suite, and run.
Further, dynamic analysis results can help eliminate redundant test cases from a test suite.
Normally the dynamic analysis results are reported in the form of a histogram or pie chart to describe the structural coverage achieved for different modules of the program.
The output of a dynamic analysis tool can be stored and printed easily to provide evidence that thorough testing has been carried out.