Я только что ответил на вопрос в 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 можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.