Defensive programming techniques

From Lazarus wiki
Revision as of 08:41, 12 February 2018 by Thaddy (talk | contribs) (→‎Range errors)
Jump to navigationJump to search

Range errors

Range errors are easy to introduce and sometimes hard to find. They can exist for years without being noticed. I have seen production units where range checks were deliberately turned off by adding {$R-} in a unit and nobody noticed this for years. When I compiled the code during a review with range checks on {$R+} I found a huge bug that potentially could crash a vital piece of software. Mind you, there can be reasons to turn range checks off but never for a whole unit or a whole program, unless it is fully tested for a release.

Let's introduce you to a small piece of code with a range bug.

program dtp_1a;
{$mode objfpc}
var
  anArray:array[0..9] of integer; // ten elements
  i:integer;
begin
  for i := 1 to 10 do 
  begin
    anArray[i] := i;
    write(anArray[i]:3);
  end;  
end.

This code compiles without error and on some systems it even runs! without error:
'fpc -glh dtp_1a.pas
Note -glh obtains line info in case of an error. Running the program yields:

dtp
  1  2  3  4  5  6  7  8  9 10

That may seem right, but is wrong! Which you know if you have spotted the bug.
Now let's see what happens when we compile with range checks:

program dtp_1b;
{$mode objfpc}{$R+}
var
  anArray:array[0..9] of integer; // ten elements
  i:integer;
begin
  for i := 1 to 10 do 
  begin
    anArray[i] := i;
    write(anArray[i]:3);
  end;  
end.

fpc -glh dtp_1b.pas
You may not expect this code to compile if you discovered the error, but unfortunately it compiles without error or warning. The fun starts when you run it:

dtp
  1  2  3  4  5  6  7  8  9Runtime error 201 at $000101B8
  $000101B8  main,  line 9 of dtp.pas
  $00010124

No heap dump by heaptrc unit
Exitcode = 201

Ok, we found a bug at line 9 of our program and 201 means range error. Useful, but not very, since we had to run the program to make it crash. Hardly acceptable. Furthermore not every programmer sees what the bug is since it occurs in a loop. Which is wrong? i or anArray[i] or both? And when it goes wrong is also not obvious to all.
Both the fp textmode IDE and Lazarus are able to debug our program, so we set a breakpoint on line 9 and press F9 a couple of times. Note I also set a watch on i. dtp 1b.png