What you effectively wrote does 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()
not guaranteed to have zero allocation of what it allocates. When you assign an instance of a new object to the varaiable interface, if the bytes are not zeros, RTL will think that an existing interface reference already exists and will try to call its _Release()
method, calling AV, because it is not backed up by an instance of the real object. You need to reset the allocated bytes in advance, then RTL will see a link to the nil
interface and will 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);
source share