Delphi Programming

  1. Home
  2. Computing & Technology
  3. Delphi Programming
Your application will be shut down!
Page 2 : The most common run-time Delphi access violations and how to prevent them.
 More of this Feature
• Page 1: Design-time AVs
 Join the Discussion
"Post your questions, concerns, views and comments to this article..."
Discuss!
 Related Resources
• Delphi IDE articles
• Handling exceptions
 Elsewhere on the Web
• AVs to PAS line numbers
• Clean Up After Yourself!
• Dr. Watson
• How to read the 'BSOD'
• GPF solve flowchart
• Troubleshooting Common Problems with Applications

It happens with any software development: you write the application, test it, and send it out into the wide world. Then a user calls up to tell you that your pride and joy has fallen flat on its face.

You might want to consider compiling your application with the {$D} compiler directive - Delphi can create map files which can be a big help in locating the source of AV errors. The Project Options dialog box (Project|Options|Linker & Compiler) lets you specify all you need. For units, the debug information is recorded in the unit file along with the unit's object code. Debug information increases the size of unit file and takes up additional memory when compiling programs that use the unit, but it does not affect the size or speed of the executable program. The Include debug info (Project|Options|Linker) and Map file (Project|Options|Linker) options produce complete line information for a given module only if you've compiled that module in the {$D+} state.

Access violations usually manifest themselves in only one aspect of the program. It is important to think about what the user was doing when the problem first occurred, and then work towards a solution from there. From the user's point of view, your application has made the user stop working, and the time spent telling you about the problem seems to be delaying you from fixing it. However, talking with the user is the only way you will find the problem and improve your application.

Now you will see how to easily find the exact routine, source code file, and line where an AV occurred when given nothing more than the crash address.

   'Search - Find Error...'
When a run-time AV occurs, the error message your user gets, looks something like:

Access violation at address
in module
Read of address

If you have your application compiled with debug information in the Delphi IDE, you can locate the line of source code corresponding to the compiled code that caused the access violation.

Non-existing object
One of the most common causes of AVs in Delphi programming is the use of an object that has not yet been created. If the second address is FFFFFFF (or 0000000) you can almost bet you are accessing an object that has not been created. For example calling a method on a form that was not auto-created and is not instantiated by the code.

procedure TfrMain.OnCreate(Sender: TObject);
var BadForm: TBadForm;
begin
  // this will generate an AV
  BadForm.Refresh;
end;

Suppose that BadForm is listed in the "Available Forms" list in the Project Options window - forms that need to be created and freed manually. In the code above the call to Refresh method of the BadForm form causes an access violation.

If you have enabled the "Stop on Delphi Exceptions" in the Language Exceptions tab on the Debugger Options window than the following message pops up:

EAccessViolation

The message states that the EAccessViolation has occurred. The EAccessViolation is the exception class for invalid memory access errors. This is what you will see while developing your application. The next message box will see the user - and the program will die:

Access Violation at run-time

Access violation at address 0043F193
in module 'Project1.exe'
Read of address 000000.

Find Error - AV
The first hex number ('0043F193') is the address of the runtime error in the compiled code (Project1.exe) were the AV occurred. In the IDE choose menu option 'Search|Find Error...', enter the address at which the error occurred ('0043F193') in the dialog and click OK. Delphi will now recompile your project and show you the line of source code were the runtime error occurred, that is, the BadForm.Refresh.

What follows is a list of the most common causes of AVs in Delphi development. This list is not, and it can't be, intended to cover all the situations in which an AV can occur. Please post your AV to the Forum - we'll try to solve them together - real life examples are normally more obscure than those that follow.

Calling a non-existing object
As stated above the most probable cause of AVs is the use of an object that has not yet been created or has already been destroyed. To prevent this kind of AV, be sure than any objects you refer to, have first been created. For example, you might be opening a Table in the form's OnCreate event when the Table component is located on a data module which has not been created yet (was removed from the auto-crete forms list).
In the next code an AV occurs after calling a method on an object (b:TBitmap) that has already been destroyed.

var b:TBitmap;
begin
 b:=TBitmap.Create;
 try
  //do something with b
 finally
  b.free;
 end; 
 ...
 //this will cause an AV - b does not longer exist
 b.Canvas.TextOut(0,0,'this is an Access Violation');
end;

Invalid API parameter
If you attempt to pass an invalid parameter to a Win API procedure an AV might occur. The best way to solve this kind of AV is to refer to the Win API help for information on the particular API call and the parameters and parameter types it expects. For example, always be sure not to pass an invalid pointer to a buffer parameter.

Let Delphi Free
When an object ownes another object, let it do the deleting. Since, by default, all forms (autocreated) are owned by the Application object, when the application terminates, it frees the Application object, which frees all forms. For example, if you have two forms (Form1/Unit1 and Form2/Unit2) both autocreated when the application starts, the next code will result in an AV:

unit Unit1;
...
uses unit2;
...
procedure TForm1.Call_Form2
begin
 Form2.ShowModal;
 Form2.Free;
 Form2.ShowModal; //AV
end;

Killing the exception
Never destroy the temporary exception object (E). Handling an exception automatically destroys the exception object. If you destroy the object yourself, the application attempts to destroy the object again, generating an access violation.

Zero:=0;
try
 dummy:= 10 / Zero;
except
 on E: EZeroDivide do
   MessageDlg('Can not divide by zero!',
               mtError, [mbOK], 0);
 E.free. // causes an access violation
end;

Indexing an empty string
An empty string has no valid data. Therefore, trying to index an empty string is like trying to access nil and will result in an access violation:

var s: string;
begin
 s:='';
 s[1]:='a'; //AV
end;

Dereferencing pointers
You must dereference the pointers, otherwise you are moving the address of the pointers and possibly corrupting other memory locations.

procedure TForm1.Button1Click(Sender: TObject);
var
  p1 : pointer;
  p2 : pointer;
begin
  GetMem(p1, 128);
  GetMem(p2, 128);
 {This line may cause an access violation}
  Move(p1, p2, 128);
 {This line is correct}
  Move(p1^, p2^, 128);
  FreeMem(p1, 128);
  FreeMem(p2, 128);
end;

   That's all folks
I hope that now, your users will scream less about how your application crashed.

Don't forget to post your questions, concerns, views and comments to this article on the Delphi Programming Forum.

First page > Preventing desing-time AVs > Page 1 , 2

Explore Delphi Programming

About.com Special Features

Delphi Programming

  1. Home
  2. Computing & Technology
  3. Delphi Programming

©2009 About.com, a part of The New York Times Company.

All rights reserved.