Software Engineering for Students A Programming Approach

Software Engineering for Students A Programming Approach Software Engineering for Students A Programming Approach

web.firat.edu.tr
from web.firat.edu.tr More from this publisher
21.08.2013 Views

17.2 Fault detection by software 241 In general, it seems that compile-time checking is better than run-time checking. However, run-time checking has the last word. It is vital because not everything can be checked at compile time. SELF-TEST QUESTION 17.2 Add to the list above checks that can only be done at run-time and therefore, by implication, cannot be done at compile-time. Incidentally, it is common practice to switch on all sorts of automatic checking for the duration of program testing, but then to switch off the checking when development is complete – because of concern about performance overheads. For example, some C++ compilers allow the programmer to switch on array subscript checking (during debugging and testing), but also allow the checking to be removed (when the program is put into productive use). C.A.R Hoare, the eminent computer scientist, has compared this approach to that of testing a ship with the lifeboats on board but then discarding them when the ship starts to carry passengers. We have looked at automatic checking for general types of fault. Another way of detecting faults is to write additional software to carry out checks at strategic times during the execution of a program. Such software is sometimes called an audit module, because of the analogy with accounting practices. In an organization that handles money, auditing is carried out at different times in order to detect any fraud. An example of a simple audit module is a method to check that a square root has been correctly calculated. Because all it has to do is to multiply the answer by itself, such a module is very fast. This example illustrates that the process of checking for faults by software need not be costly – either in programming effort or in run-time performance. SELF-TEST QUESTION 17.3 Devise an audit module that checks whether an array has been sorted correctly. Another term used to describe software that attempts to detect faults is defensive programming. It is normal to check (validate) data when it enters a computer system – for example, numbers are commonly scrupulously checked to see that they only contain digits. But within software it is unusual to carry out checks on data because it is normally assumed that the software works correctly. In defensive programming the programmer inserts checks at strategic places throughout the program to provide detection of design errors. A natural place to do this is to check the parameters are valid at the entry to a method and then again when a method has completed its work. This approach has been formalized in the idea of assertions, explained below.

242 Chapter 17 ■ Software robustness 17.3 ● Fault detection by hardware We have already seen how software checks can reveal faults. Hardware also can be vital in detecting consequences of such software errors as: ■ division by zero, more generally arithmetic overflow ■ an array subscript outside the range of the array ■ a program which tries to access a region of memory that it is denied access to, e.g. the operating system. Of course hardware also detects hardware faults, which the hardware often passes on to the software for action. These include: ■ memory parity checks ■ device time-outs ■ communication line faults. Memory protection systems One major technique for detecting faults in software is to use hardware protection mechanisms that separate one software component from another. (Protection mechanisms have a different and important role in connection with data security and privacy, which we are not considering here.) A good protection mechanism can make an important contribution to the detection and localization of bugs. A violation detected by the memory protection mechanism means that a program has gone berserk – usually because of a design flaw. To introduce the topic we will use the analogy of a large office block where many people work. Along with many other provisions for safety, there will usually be a number of fire walls and fire doors. What exactly is their purpose? People were once allowed to smoke in offices and public buildings. If someone in one office dropped a cigarette into a waste paper basket and caused a fire, the fire walls helped to save those in other offices. In other words, the walls limited the spread of damage. In computing terms, does it matter how much the software is damaged by a fault? – after all it is merely code in a memory that can easily be re-loaded. The answer is “yes” for two reasons. First, the damage caused by a software fault might damage vital information held in files, damage other programs running in the system or crash the complete system. Second, the better the spread of damage is limited, the easier it will be to attempt some repair and recovery. Later, when the cause of the fire is being investigated, the walls help to pinpoint its source (and identify the culprit). In software terminology, the walls help find the cause of the fault – the bug. One of the problems in designing buildings is the question of where to place the firewalls. How many of them should there be, and where should they be placed? In software language, this is called the issue of granularity. The greater the number of walls, the more any damage will be limited and the easier it will be to find the cause. But walls are expensive and they also constrain normal movement within the building.

17.2 Fault detection by software 241<br />

In general, it seems that compile-time checking is better than run-time checking.<br />

However, run-time checking has the last word. It is vital because not everything can<br />

be checked at compile time.<br />

SELF-TEST QUESTION<br />

17.2 Add to the list above checks that can only be done at run-time and<br />

there<strong>for</strong>e, by implication, cannot be done at compile-time.<br />

Incidentally, it is common practice to switch on all sorts of automatic checking <strong>for</strong><br />

the duration of program testing, but then to switch off the checking when development<br />

is complete – because of concern about per<strong>for</strong>mance overheads. For example,<br />

some C++ compilers allow the programmer to switch on array subscript checking (during<br />

debugging and testing), but also allow the checking to be removed (when the program<br />

is put into productive use). C.A.R Hoare, the eminent computer scientist, has<br />

compared this approach to that of testing a ship with the lifeboats on board but then<br />

discarding them when the ship starts to carry passengers.<br />

We have looked at automatic checking <strong>for</strong> general types of fault. Another way of<br />

detecting faults is to write additional software to carry out checks at strategic times<br />

during the execution of a program. Such software is sometimes called an audit module,<br />

because of the analogy with accounting practices. In an organization that handles<br />

money, auditing is carried out at different times in order to detect any fraud. An<br />

example of a simple audit module is a method to check that a square root has been<br />

correctly calculated. Because all it has to do is to multiply the answer by itself, such a<br />

module is very fast. This example illustrates that the process of checking <strong>for</strong> faults by<br />

software need not be costly – either in programming ef<strong>for</strong>t or in run-time per<strong>for</strong>mance.<br />

SELF-TEST QUESTION<br />

17.3 Devise an audit module that checks whether an array has been sorted<br />

correctly.<br />

Another term used to describe software that attempts to detect faults is defensive programming.<br />

It is normal to check (validate) data when it enters a computer system – <strong>for</strong><br />

example, numbers are commonly scrupulously checked to see that they only contain<br />

digits. But within software it is unusual to carry out checks on data because it is normally<br />

assumed that the software works correctly. In defensive programming the programmer<br />

inserts checks at strategic places throughout the program to provide detection<br />

of design errors. A natural place to do this is to check the parameters are valid at the<br />

entry to a method and then again when a method has completed its work. This<br />

approach has been <strong>for</strong>malized in the idea of assertions, explained below.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!