[英]Strange AV when storing an Delphi interface reference
我在以下代碼中收到意外的訪問沖突錯誤:
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.
我知道接口應該以不同的方式使用。 但是我正在研究使用這種方法的遺留代碼庫。 而且我很驚訝地發現,保留SizeOf(ITest)內存並將ITest放在那里是不夠的。
現在有趣的是,如果我改變第一行
GetMem(p, 21);
比AV消失了。 (20個字節或更少的失敗)。 對此有何解釋?
(我使用的是Delphi XE2 Update 4 + HotFix)
請不要評論代碼是多么可怕或建議如何正確編碼。 請回答為什么有必要保留21個字節而不是SizeOf(ITest)= 4?
你有效寫的是在幕后做以下邏輯:
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()
不保證將其分配的內容清零。 當你將新對象實例分配給varaiable接口時,如果字節不是零,RTL會認為已經有一個現有的接口引用,並會嘗試調用它的_Release()
方法,導致AV因為它沒有支持一個真實的對象實例。 您需要預先將分配的字節清零,然后RTL將看到一個nil
接口引用而不再嘗試調用其_Release()
方法:
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.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.