Я только что ответил на вопрос в newsgroup, просто делая copy-and-paste своего старого поста. Повторное использование является благим делом, так что я решил поместить это ещё и в свой блог. Вот этот пост: "Просто забавы ради я сделал несколько подпрограмм, которые проверяют, является ли указатель ссылкой на допустимый объект (экземпляр класса). Этот код основывается на некоторых типах и подпрограммах из книги Ray Lischner-а "Secrets of Delphi 2" (модуль S_VMT). Заметьте, что этот код привязан к D3. Для других версий Delphi могут потребоваться изменения.
uses S_VMT; function ValidPtr(P: pointer; Size: Cardinal): boolean; begin Result := not IsBadReadPtr(P, Size); end; function ValidObjType(Obj: TObject; ClassType: TClass): boolean; begin Result := Assigned(Obj) and ValidPtr(Pointer(Obj), SizeOf(TObject)) and ValidPtr(Pointer(Obj), ClassType.InstanceSize); end; type PClass = ^TClass; function ValidPShortString(S: PShortString): boolean; begin Result := ValidPtr(S, SizeOf(Byte)) and ValidPtr(S, Ord(S^[0])) ; end; function ValidClassParent(ClassParent: PClass): boolean; begin if ClassParent = nil then Result := true else if ValidPtr(ClassParent, SizeOf(ClassParent^)) then Result := (ClassParent^ = nil) or ValidClassType(ClassParent^) else Result := false; end; function ValidClassType(ClassType: TClass): boolean; var Vmt: PVmt; begin Vmt := GetVmt(ClassType); Result := ValidPtr(Vmt, SizeOf(Vmt^)) and (Vmt^.SelfPtr = ClassType) and ValidPShortString(Vmt^.ClassName) and ValidClassParent(PClass(Vmt^.ClassParent)) ; end; function ValidObj(Obj: TObject): boolean; begin Result := Assigned(Obj) and ValidPtr(PClass(Obj), SizeOf(TClass)) and ValidClassType(Obj.ClassType) and ValidPtr(Pointer(Obj), Obj.InstanceSize); end;Надо полагать, что этот способ не пуленепробиваем, но должен работать во многих случаях. Он работает, проверяя допустимость указателя, используя функцию IsBadReadPtr, затем проверяет что VMT-указатель для данного предполагаемого объекта корректен. Использование этого кода не рекомендуется - вместо этого используйте установку указателей в nil после удаления объекта".
Обновление: я нашёл другой старый пост с более простым (и, вероятно, более безопасным) способом проверки:
function ValidateObj(Obj: TObject): Pointer; type PPVmt = ^PVmt; PVmt = ^TVmt; TVmt = record SelfPtr : TClass; Other : array[0..17] of pointer; end; var Vmt: PVmt; begin Result := Obj; if Assigned(Result) then try Vmt := PVmt(Obj.ClassType); Dec(Vmt); if Obj.ClassType <> Vmt.SelfPtr then Result := nil; except Result := nil; end; end;Заметьте, что этот вариант кода написан для D6 и D7 (IIRC). Для других версий вам может понадобится обновить жёстко зашитое волшебное число (17).
Обновление: заметьте, что "новый" FastMM Pierre-а (а, следовательно, и менеджер памяти в D2006 и выше) более агрессивно повторно использует память, чем старый менеджер памяти, так что бы более вероятно можете получить ложно-положительный ответ от этого кода, особенно если память объекта была освобождена, а затем повторно использована для другого объекта (потенциально: другого типа).
Как обычно: используйте этот хак с осторожностью и недоверием.
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.