2010-11-18 82 views
1

即時得到以下德爾福訪問衝突讀取對象從TStringsList

Access violation at address 00404340 in module 'test.exe'. Read of address FFFFFFD5

用下面的代碼

var 
List: TStrings; 

在創建科:
List:= TStringList.Create;

添加到列表:
Result := List.AddObject('hi', aCreatedObject); MessageDlg(FunctionHookList.Objects[Result].ClassName, mtInformation, [mbOK], 0);

消息對話框顯示正確的類名

但是當我做後,

i := list.IndexOf('hi'); 
    if i >= 0 then 
     if list.Objects[i] <> nil then 
     if assigned(list.Objects[i]) then 
      begin 
      tmp := list.Objects[i]; 
      if tmp <> nil then 
       MessageDlg(tmp.ClassName, mtInformation, [mbOK], 0); //******* 
      end; 

我得到的訪問衝突高於上//*******

我知道有有一些重複代碼,但我試圖檢查'所有'

+1

當你說「以後」時,你是什麼意思?也許aCreatedObject在那個時候已經被銷燬,並且list.Objects [i]返回一個無效的對象。請在變量聲明的一個完整函數中發佈示例。 – Ozan 2010-11-18 05:39:01

+0

如果索引i處的對象爲零,則您的代碼會檢查兩次,如果指定了對象,則檢查兩次。您可以將Objects [i]分配給tmp一次,然後檢查tmp:'if i> = 0,然後開始tmp:= Objects [i];如果分配了(tmp),那麼...' – mjn 2010-11-18 08:10:35

+0

@Ozan,可能是aCreatedObject可能已經被銷燬,我認爲如果是的話,我過度使用'<> nil'和'assigned'就會捕獲它。 – 2010-11-18 23:26:46

回答

1

請注意,分配不檢查任何東西,除了。如果你將一個對象放在字符串列表中,將其釋放,然後檢查字符串列表,它會告訴你還有一個對象。檢查這個例子:

var 
    o: TObject; 
begin 
    o := TObject(42 {just a random number}); 
    if Assigned(o) then 
    ShowMessage(o.ClassName); 
end; 

因此,幾乎所有的檢查都是有效的,除了分配。它只檢查對象是否包含除nil以外的任何其他值,這與您在上面的行上執行的檢查基本相同。

2

看起來您的程序正在從空指針的負偏移量讀取。偏移量與存儲在VMT中的類名偏移量相差一個,表明對象存儲其指針VMT的字段保存地址1而不是其類的VMT的實際地址。

這會引發您是否確實在該列表中存儲了有效的對象引用的問題。您正在向List添加某些內容,但爲了測試它的工作情況,您正在輸出FunctionHookList中某個對象的ClassName值。有什麼理由相信這些是同一個對象?檢查構建對象的方式,然後檢查賦予aCreatedObject變量值的賦值語句。查找可疑的內存操作,例如調用MoveTStream.Read,其中您指定了錯誤的目標指針或錯誤的字節數,從而覆蓋該對象的一部分。

要幫助瞭解發生了什麼,請在列表中的對象上調用ClassType函數。 (這通常是安全的,因爲只要指針存儲在對象參考點某處中,您將獲得一個值,也許不是有效的值,但至少它不會崩潰。導致您的課程預計在列表中。例如,如果你在列表存儲在TFont,然後測試:

tmp := list.Objects[i]; 
if tmp.ClassType <> TFont then 
    ShowMessage(Format('Expected %p but got %p instead', 
    [Pointer(TFont), Pointer(tmp.ClassType)]));