Avoiding using stale pointers
I've written a very simple unit, and devised some simple methods, to help prevent the usage of stale pointers. My biggest recommendation is to add an 'initialization' section to ALL UNITS WHICH CONTAIN POINTER OR OBJECT VARIABLES and set all the pointers (object variables are really pointers too) to nil. This will ensure that the pointers are all nilified before they are ever used. Then, simply reset pointers to nil after freeing them. My unit contains a Nilify() function for setting pointers to nil, as well as special versions of Free, Dispose, and FreeMem (called NilXXX) which test for nil before freeing memory, and resets the pointer to nil once it has been freed. I've also included a special version of Assigned(), called IsNil(), which takes a const parameter instead of a var parameter, which means you can use it on properties, etc.
This unit, of course, does nothing to the VCL, so you can still get stale pointers back from the VCL... But strict adherence to the functions in this unit should help ensure YOU don't make a mistake. The only condition on its use/distribution is that you forward any changes or suggestions you might have to me. Use it and program in good health!
unit Pointers;
{
Author: David S. Becker (dsb@plaza.ds.adp.com)
Date: 1/27/97
Copyright: None
Distribution Rights: Free, unlimited use, provided you forward any and all
changes or suggestions you have to me.
This unit was created to aid in the managment of pointers and objects. Since
the compiler does not initialize pointers or objects to nil, and does not set
them to nil when freed, it is possible to accidentally reference stale
pointers. For this reason, I recommend you add an 'initialization' section to
all units and call Nilify() on all pointers/objects in that unit. This
will ensure that all pointers/objects start off as nil. Furthermore, you
should use the NilFree (for objects), NilDispose (for pointers created with
New), and NilFreeMem (for pointers created with GetMem) instead of their
standard counterparts. These procedures are safe to call on nil pointer/
objects, as they check for nil before performing any action. After freeing
the memory allocated to the pointer/object, they reset the pointer to nil. If
you are strict in your use of these procedures, your risk of accessing stale
pointer is greatly reduced. (Of course, you can still get stale pointers from
the VCL as it obviously doesn't use these functions.)
}
{==============================================================================}
interface
{------------------------------------------------------------------------------}
{ Checks a pointer against nil }
{ NOTE: This function differs from Assigned() in that Assigned() requires a }
{ variable, whereas IsNil() does not. }
function IsNil(const p: Pointer): Boolean;
{ Sets a pointer to nil }
procedure Nilify(var p);
{ Frees a non-nil object, then sets it to nil }
procedure NilFree(o: TObject);
{ Frees a non-nil pointer created by New, then sets it to nil }
procedure NilDispose(var p: Pointer);
{ Frees a non-nil pointer, then sets it to nil }
procedure NilFreeMem(var p: Pointer; size: Word);
{==============================================================================}
implementation
{------------------------------------------------------------------------------}
function IsNil(const p: Pointer): Boolean;
begin
Result := (p = nil);
end;
{------------------------------------------------------------------------------}
procedure Nilify(var p);
begin
Pointer(p) := nil;
end;
{------------------------------------------------------------------------------}
procedure NilFree(o: TObject);
begin
if not IsNil(o) then begin
o.Free;
Nilify(o);
end;
end;
{------------------------------------------------------------------------------}
procedure NilDispose(var p: Pointer);
begin
if not IsNil(p) then begin
Dispose(p);
Nilify(p);
end;
end;
{------------------------------------------------------------------------------}
procedure NilFreeMem(var p: Pointer; size: Word);
begin
if not IsNil(p) then begin
FreeMem(p,size);
Nilify(p);
end;
end;
end.
|