Нарушение прав доступа Delphi Чтение объекта из 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;  

я получаю нарушение прав доступа выше в строке //*******

Я знаю, что там есть дублированный код, но я пытался проверить 'все'


person Christopher Chase    schedule 18.11.2010    source источник
comment
Что вы имеете в виду, когда говорите позже? Возможно, aCreatedObject был уничтожен в это время, и list.Objects[i] возвращает недопустимый объект. Пожалуйста, опубликуйте пример в рамках одной полной функции с объявлениями переменных.   -  person Ozan    schedule 18.11.2010
comment
ваш код дважды проверяет, является ли объект с индексом i нулевым, и один раз, если он назначен. Вы можете назначить Objects[i] для tmp один раз и проверить tmp: if i >= 0 then begin tmp := Objects[i]; if Assigned(tmp) then ...   -  person mjn    schedule 18.11.2010
comment
@Ozan, возможно, что aCreatedObject мог быть уничтожен, я думал, что мое чрезмерное использование <> nil и assigned поймает его, если это так.   -  person Christopher Chase    schedule 19.11.2010
comment
@mjustin мой исходный код выглядел примерно так, но я продолжаю добавлять проверки в надежде найти какой-то ответ. я собирался упростить его после того, как он заработал   -  person Christopher Chase    schedule 19.11.2010


Ответы (2)


Обратите внимание, что Assigned ничего не проверяет, кроме nil. Если вы поместите объект в список строк, освободите его, а затем проверите список строк, он скажет вам, что объект все еще существует. Проверьте этот пример:

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

Так что почти все ваши чеки действительны, кроме назначенных. Он только проверяет, содержит ли объект какое-либо другое значение, кроме nil, что в основном является той же проверкой, которую вы выполняете в строке выше.

person GolezTrol    schedule 18.11.2010

Похоже, ваша программа читает с отрицательного смещения нулевого указателя. Смещение отличается на единицу от смещения, в котором имя класса хранится в VMT, что позволяет предположить, что поле, в котором объект хранит свой VMT содержит адрес 1 вместо фактического адреса VMT своего класса.

Это ставит под сомнение, действительно ли вы сохранили действительную ссылку на объект в этом списке. Вы добавляете что-то к List, но затем, чтобы проверить, работает ли это, вы печатаете значение ClassName некоторого объекта в FunctionHookList. Какие основания полагать, что это один и тот же объект? Проверьте, как вы построили объект, а затем проверьте оператор присваивания, который дает значение переменной aCreatedObject. Ищите сомнительные операции с памятью, такие как вызов Move или TStream.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)]));
person Rob Kennedy    schedule 18.11.2010