Design - programming Cmpe 450 Fall 2008
Dynamic Analysis Software quality Design carefully from the start Simple and clean Fewer errors Finding errors introduced in coding Dynamic techniques Executing program and observe its behaviour
Static Analysis Ensure quality before execution Design evaluation Code analysis Manual reviews, tools
Dynamic Techniques Rush through specs and designs Fix up later Design and implementation mixed, hard to find errors Cost of fixing an error is higher at later stages
Static Techniques All errors can not be caught statistically “testing can reveal the presence of errors but never their absence”
Defensive Programming To increase reliability of the program by inserting redundant checks Invariants Runtime assertions Testing invariants explicitly
Defensive Programming To make code bug free in the most effective way. Always better to write a good code from scratch than fixing a bad code When to write runtime assertions? As you write the code, not later...
Runtime Assertions- guidelines Check the precondition at the start of the procedure No room for misunderstandings about interfaces between procedures Check the postcondition Self check Write assertions when operation is about to be performed that has some external effect
Runtime assertions- mistakes Runtime assertions slow execution down Write them in testing and turn them off in the official release? WRONG WRONG PRACTICE
Debugging
Debugging is the least predictable software development activity. One usually doesn’t know in advance whether finding the next bug will take five minutes or five weeks. Some people debug using their intuition. From the nature of the symptom, they can go directly to the parts of the program that are most likely to contain the error. While such intuition is useful and can be developed if you learn from experience, it is not necessary; there is a general approach to debugging that does not need it.
General Approach When you run a buggy program on some test data, initially everything is all right (variables have the right values, the right output is produced, control takes the expected path). Things go wrong after a point in time at which a buggy statement is executed. One can identify the buggy statement by identifying this point in time. This of course requires the programmer to be able to tell what the right values of variables are at every point in the program. For programmers other than the original authors, and sometimes even for them, this requires documentation of what the code is meant to do. If this is missing, it has to be recreated.
The suspect period The suspect period is initially the entire run, the whole sequence of statements executed by the program. At some point in the middle of the run, you can check whether everything is all right. If not, you can eliminate the part of the suspect period after the point; the first bug is before that point. There may also be bugs after that point, but you should look for them after the first bug is fixed. If yes, you can eliminate the part of the suspect period before the point; the first bug detectable by this test case is after that point. Any bugs before that point need another test case.
Binary Search
Approximating binary search
Minimizing the failed test case
Diagnostic printfs
Debuggers
Forward Execution
Choosing breakpoints
Breakpoints on functions
Global variables
Tracking errors to their source
Core files
Wild pointer errors
Laws of debugging
Some possibly untrue assumptions
Fixing bugs
Type safety
The magical number seven
Coping with complexity
Abstraction
Modules
Undersanding modular programs
Information hiding
Language support
Declaration vs definition
Type safety convention, part 1
Quiz Is there type safety in C? Explain yes or no on the sample piece of code. What is the problem with this code?
Example
C’s lack of type safety
The problem