I was doing some testing today (Mac) and discovered that calling Free on a nil object didn’t cause a EAccessViolation exception. Why doesn’t that crash?
var
c: TObject;
begin
c := nil;
c.Free;Regards,
Ryan Joseph

Mailing lists / fpc-pascal / 2018-07
18 messages · 6 people · –
Reply by email Subscribe to this list Your subscription
Read-only archive. Use j and k to move between messages.
I was doing some testing today (Mac) and discovered that calling Free on a nil object didn’t cause a EAccessViolation exception. Why doesn’t that crash?
var
c: TObject;
begin
c := nil;
c.Free;Regards,
Ryan Joseph
Ryan Joseph wroteI was doing some testing today (Mac) and discovered that calling Free on a nil object didn’t cause a EAccessViolation exception. Why doesn’t that crash?
It is by design.
And - OMG !! - it is even documented:
https://www.freepascal.org/docs-html/current/rtl/system/tobject.free.html
Michael.
There is no need to search the docs, it is even more quick just jump to the implementation of free and see what it does :)
It is by design. And - OMG !! - it is even documented:…
I never use Free directly so I had no idea. How is that even accomplished in the language? I thought it was just a method and behaved accordingly.
If it is magic then how do we call other methods on nil objects? There are times that would be handy if I could control it.
Regards,
Ryan Joseph
It's not a magic, it's explicit check for the value of "Self" within a method.
Self would point to an actual instance of an object, if it's nil. Free method won't do anything.
type
TRobust = class(TObject)
public
v : Integer;
procedure RobustMethod;
end;
procedure TRobust.RobustMethod;
begin
if Self = nil then Exit; // remove or comment out this line to start
getting AVs
v := 5;
end;
var
r : TRobust;
begin
r := nil;
r.RobustMethod;
end.You could consider this a sanity check, similar to checking any other input parameters.
thanks,
Dmitry
I had no idea you could do that!
I’m totally confused now. Since when was it ok to call methods on nil objects? According to this test not only can you call methods on nil objects but it calls the method statically (like a class method), i.e the test prints “DoThis”. How is that possible?
type
TMyClass = class
procedure DoThis;
end;
procedure TMyClass.DoThis;
begin
writeln('DoThis');
end;
var
obj: TMyClass;
begin
obj := nil;
obj.DoThis;Regards,
Ryan Joseph
[...] I’m totally confused now. Since when was it ok to call methods on nil objects?
You can't if you compile with -CR.
The RTL is not compiled with objectchecks, so it works there.
According to this test not only can you call methods on nil objects but it calls the method statically (like a class method), i.e the test prints “DoThis”. How is that possible?
Self on x86_64 target is just a hidden argument.
It won't work with virtual methods.
Mattias
This is all news to me. I had no idea I was possibly compiling programs where I could call nil objects.
How do I disable this? I just ran this test program with -CR and I still calls the method statically.
Ryans-MacBook-Pro-2:~ ryanjoseph$ fpc -CR /Users/ryanjoseph/Desktop/macro_test/obj_test.pas Free Pascal Compiler version 3.0.4 [2017/11/26] for x86_64 Copyright (c) 1993-2017 by Florian Klaempfl and others Target OS: Darwin for x86_64
Compiling /Users/ryanjoseph/Desktop/macro_test/obj_test.pas Assembling (pipe) /Users/ryanjoseph/Desktop/macro_test/obj_test.s Linking /Users/ryanjoseph/Desktop/macro_test/obj_test 19 lines compiled, 0.1 sec
Ryans-MacBook-Pro-2:~ ryanjoseph$ /Users/ryanjoseph/Desktop/macro_test/obj_test DoThis
{$mode objfpc}
program obj_test;
type
TMyClass = class
procedure DoThis;
end;
procedure TMyClass.DoThis;
begin
writeln('DoThis');
end;
var
obj: TMyClass;
begin
obj := nil;
obj.DoThis;
end.Regards,
Ryan Joseph
I had no idea you could do that! I’m totally confused now. Since when was it ok to call…
Ryan Joseph wroteI had no idea you could do that!
Obviously, it speaks high of your abilities ;)
You've been able to accomplish your tasks without use of hacks (of any kind), playing strict by the rules.
I’m totally confused now. Since when was it ok to call methods on nil
that at any time on either nil-ed or uninitialized object as long as the method doesn't try to access and invalid memory.
The example (compiled for i386 and not using -CR works as expected)
type
TRobust = class(TObject)
public
v : Integer;
function Max(a,b: Integer): Integer;
end;
function TRobust.Max(a,b: Integer): Integer;
begin
if a>b then Result:=a
else Result:=b;
end;
var
r : TRobust;
begin
r := nil;
writeln(r.Max(5,10));
end.However such behavior, would be RTL specific - it's all about how the compiler would generate such call. If it would attempt to access any field (i.e. VMT) related to the instance of the object itself (rather than the class), there's a high chance it would fail.
And that's why having -CR enabled during development is generally a very good idea.
From high-level (OOP) such actions are not welcomed (and are enforced using
-CR in case of FPC).
In order to have robust, maintainable and portable (to either other platform or even language) a developer should respect high-level rules and never depend on low-level rules to be the same on any platform.
thanks,
Dmitry
Do I have permission to quote you the next time someone starts about how the lifetimes of interfaces are managed slightly differently in FPC and Delphi ?
:)
Michael.
On Fri, Jul 27, 2018 at 3:22 PM, Michael Van Canneyt <
Permission granted.
I thought all (COM) interfaces have been resolved, back in 2.6?
This is all news to me. I had no idea I was possibly compiling programs where I could…
[...] How do I disable this? I just ran this test program with -CR and I still calls the method statically.
You are right. I just tested myself.
Either I'm confusing the flag or it has been changed. Once upon a time Lazarus used the same trick and I had to change the code as some users wanted use the flag.
Mattias
Do you need me to file a bug report? This caused me a big headache this morning that I would like to avoid in the future. Off the top of my head I’m not aware of any time I’d want a call to nil to not fire an exception, except for calling Free perhaps since this is the documented behavior.
Thanks for straitening this out for me, I thought I was losing my mind. :)
Regards,
Ryan Joseph
This is all news to me. I had no idea I was possibly compiling programs where I could…
Normal, non-virtual methods are essentially ordinary functions/procedures. In contrast to static functions/procedures they have a hidden parameter that contains the value of Self. As Self is merely a pointer there is no problem if Self should be Nil as long as it isn't dereferenced (which happens if you access a field or a call a virtual method).
Calling a virtual method would fail immediately.
How do I disable this? I just ran this test program with -CR and I still calls the method statically.
The method is always called statically, -CR doesn't change anything there. Calling a virtual method however would fail with EObjectCheck instead of EAccessViolation.
The method you provided below would not fail anyway, because it doesn't dereference Self. If you'd however access for example a field of your class then a check should be inserted inside the method. For some reason it isn't however and *that* is the bug.
Regards,
Sven
On Jul 28, 2018, at 2:03 AM, Sven Barth via fpc-pascal wrote: The method you provided below would not fail anyway, because it doesn't dereference Self. If you'd however access for example a field of your class then a check should be inserted inside the method. For some reason it isn't however and *that* is the bug.
Just getting back to this now.
Thanks for the description, I didn’t know FPC behaved that way but it’s good to know.
However, I’ve never had a use for this (outside of calling Free as I learned and the way I’ve always programmed Pascal, accessing nil is an error or undefined behavior so I avoid it meticulously.
How can I disable this so calling a method on nil gives an error?
Regards,
Ryan Joseph
Ryan Joseph schrieb am Mo., 30. Juli 2018,
18:05:
If the method doesn't access Self then there is nothing you can do.
Regards,
Sven
On Jul 30, 2018, at 11:08 PM, Sven Barth via fpc-pascal wrote: If the method doesn't access Self then there is nothing you can do.
Is this something the compiler team would be interested in adding? I’d like to get an error when calling methods on nil. It’s seems like pretty basic type safety stuff to me.
Regards,
Ryan Joseph
Ryan Joseph schrieb am Di., 31. Juli 2018,
18:15:
No, because calling methods like Free would break as well and there is enough code out there that relies on that behavior. Also for methods that don't access Self it really is not important whether Self is valid or not. And for the other cases (which are the majority btw) there is functionality for that even if it is currently buggy.
Regards,
Sven