【问题标题】:Delphi Access violation Reading Object From TStringsListDelphi访问冲突从TStringsList读取对象
【发布时间】:2010-11-18 05:16:11
【问题描述】:

我得到以下内容

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;  

我在//******* 行上遇到了上述访问冲突

我知道那里有一些重复的代码,但我试图检查 'everything'

【问题讨论】:

  • 你说的“稍后”是什么意思?可能当时 aCreatedObject 已被销毁,并且 list.Objects[i] 返回一个无效对象。请在一个完整的函数中发布一个带有变量声明的示例。
  • 如果索引 i 处的对象为 nil,您的代码会检查两次,如果已分配,则检查一次。您可以将 Objects[i] 分配给 tmp 一次并检查 tmp:if i &gt;= 0 then begin tmp := Objects[i]; if Assigned(tmp) then ...
  • @Ozan,aCreatedObject 可能已被破坏,我认为我过度使用 &lt;&gt; nilassigned 会抓住它。
  • @mjustin 我的原始代码确实看起来有点像,但我不断添加检查以希望找到一些答案。我打算'在它开始工作后'简化它

标签: delphi delphi-7 access-violation


【解决方案1】:

看起来您的程序正在读取空指针的负偏移量。偏移量与类名在 VMT 中存储的偏移量相差 1,这表明对象存储其 VMT 指针的字段保存的是地址 1,而不是其类的 VMT 的实际地址。

这让人怀疑您是否真的在该列表中存储了有效的对象引用。您正在向List 添加一些内容,但是为了测试它是否有效,您将在FunctionHookList 中打印某个对象的ClassName 值。有什么理由相信它们是同一个对象?检查您是如何构造对象的,然后检查为aCreatedObject 变量赋值的赋值语句。查找有问题的内存操作,例如调用 MoveTStream.Read,在其中指定了错误的目标指针或错误的字节数,从而覆盖了对象的一部分。

为了帮助了解发生了什么,请对列表中的对象调用ClassType 函数。 (这通常可以安全调用,因为只要存储在对象引用中的指针指向 somewhere,您就会得到一个值。可能不是 valid 值,而是在至少它不会崩溃。)将结果与您期望在列表中的类进行比较。例如,如果您在列表中存储了一个TFont,那么测试一下:

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

【讨论】:

    【解决方案2】:

    请注意,Assigned 不检查任何内容,除了 nil。如果你把一个对象放在字符串列表中,释放它,然后检查字符串列表,它会告诉你还有一个对象。检查这个例子:

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

    所以几乎所有的支票都是有效的,除了分配的。它只检查对象是否包含除 nil 之外的任何其他值,这与您在上面的行中执行的检查基本相同。

    【讨论】:

      猜你喜欢
      • 2018-08-31
      • 2013-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多