I am getting an unexpected Access Violation error in the following code:
program Project65;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils;
type
ITest = interface
end;
TTest = class(TInterfacedObject, ITest)
end;
var
p: ^ITest;
begin
GetMem(p, SizeOf(ITest));
p^ := TTest.Create; // AV here
try
finally
p^ := nil;
FreeMem(p);
end;
end.
I know that interfaces should be used differently. However I am working on a legacy codebase which uses this approach. And I was very surprised to see that it is not sufficient to reserve SizeOf(ITest) memory to put an ITest there.
Now interestingly if I change the first line to
GetMem(p, 21);
than the AV is gone. (20 bytes or less fails). What is the explanation to this?
(I am using Delphi XE2 Update 4 + HotFix)
Please don't comment on how horrible the code is or suggest how this could be coded properly. Instead please answer why is it necessary to reserve 21 bytes instead of SizeOf(ITest) = 4?
What you have effectively written is doing the following logic behind the scenes:
var
p: ^ITest;
begin
GetMem(p, SizeOf(ITest));
if p^ <> nil then p^._Release; // <-- AV here
PInteger(p)^ := ITest(TTest.Create);
p^._AddRef;
...
if p^ <> nil then p^._Release;
PInteger(p)^ := 0;
FreeMem(p);
end;
GetMem()
is not guaranteed to zero out what it allocates. When you assign the new object instance to the interface varaiable, if the bytes are not zeros, the RTL will think there is already an existing interface reference and will try to call its _Release()
method, causing the AV since it is not backed by a real object instance. You need to zero out the allocated bytes beforehand, then the RTL will see a nil
interface reference and not try to call its _Release()
method anymore:
program Project65;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils;
type
ITest = interface
end;
TTest = class(TInterfacedObject, ITest)
end;
var
p: ^ITest;
begin
GetMem(p, SizeOf(ITest));
try
FillChar(p^, SizeOf(ITest), #0); // <-- add this!
p^ := TTest.Create; // <-- no more AV
try
...
finally
p^ := nil;
end;
finally
FreeMem(p);
end;
end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With