2

In the following example:

program DisposeProblem;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  Person = record
    name: string;
    age: Integer;
  end;

var
  p: ^Person;

begin
  p := nil;
  Dispose(nil); // OK
  Dispose(p); // AV
end.

Why is the first Dispose() call OK, while the second causes an access violation error? When I step through the code, the first Dispose() calls System._FreeMem(), while the second calls System._Dispose(), but I don't understand why this is the case. I would like to understand this behavior so I can know when it is safe to call Dispose() on a nil pointer.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
KleberPF
  • 120
  • 1
  • 7

1 Answers1

8

I would like to understand this behavior so I can know when it is safe to call Dispose() on a nil pointer.

It is never OK to call Dispose() on a nil pointer variable. The RTL expects the variable to point at valid memory allocated with New(), and so will unconditionally try to finalize whatever data/object is being pointed at. Passing in a pointer variable that is nil leads to undefined behavior and will likely crash.

Dispose(nil) is effectively a no-op. The compiler knows the nil literal can't possibly point at a data type that needs to be finalized, so it doesn't need to call System._Dispose(), hence it calls System._FreeMem() instead (why it calls anything at all, I don't know).

System._FreeMem() allows nil as input, it will simply exit without doing anything. However, System._Dispose() on a pointer variable does not allow nil as input (and never has).

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Thanks for the quick answer. Is it a good practice to have a function like `SafeDispose` that checks for nil first and use that when appropriate? Also, my misconception came from this quote: "Dispose quietly ignores an attempt to free a nil pointer" from [here](https://www.oreilly.com/library/view/delphi-in-a/1565926595/re68.html), which I guess is not a very good source. – KleberPF Jan 23 '23 at 19:52
  • I don't know what Ray Lischner was referring to. Looking at the actual source code for `System._Dispose()` in several versions going back many years, it definitely does not allow `nil` as input. – Remy Lebeau Jan 23 '23 at 20:04
  • No it's not good practise to write a SafeDispose function like that. Why don't you know that your allocation succeeded? – David Heffernan Jan 23 '23 at 21:43
  • @DavidHeffernan: You may have code that is ambiguous in terms of allocating or not... – HeartWare Jan 24 '23 at 06:32