uses
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF }
TypInfo;
function IsValidObject(p: PPointer): Boolean;
{$IFDEF MSWINDOWS}
var
memInfo: TMemoryBasicInformation;
{$ENDIF}
function IsValidAddress(address: Pointer): Boolean;
begin
// Must be above 64k and 4 byte aligned
if (UIntPtr(address) > $FFFF) and (UIntPtr(address) and 3 = 0) then
begin
{$IFDEF MSWINDOWS}
// do we need to recheck the virtual memory?
if (UIntPtr(memInfo.BaseAddress) > UIntPtr(address))
or ((UIntPtr(memInfo.BaseAddress) + memInfo.RegionSize) < (UIntPtr(address) + SizeOf(Pointer))) then
begin
// retrieve the status for the pointer
memInfo.RegionSize := 0;
VirtualQuery(address, memInfo, SizeOf(memInfo));
end;
// check the readability of the memory address
if (memInfo.RegionSize >= SizeOf(Pointer))
and (memInfo.State = MEM_COMMIT)
and (memInfo.Protect and (PAGE_READONLY or PAGE_READWRITE
or PAGE_WRITECOPY or PAGE_EXECUTE or PAGE_EXECUTE_READ
or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY) <> 0)
and (memInfo.Protect and PAGE_GUARD = 0) then
{$ENDIF}
Exit(True);
end;
Result := False;
end;
begin
Result := False;
if Assigned(p) then
try
{$IFDEF MSWINDOWS}
memInfo.RegionSize := 0;
{$ENDIF}
if IsValidAddress(p)
// not a class pointer - they point to themselves in the vmtSelfPtr slot
and not (IsValidAddress(PByte(p) + vmtSelfPtr)
and (p = PPointer(PByte(p) + vmtSelfPtr)^)) then
if IsValidAddress(p^) and IsValidAddress(PByte(p^) + vmtSelfPtr)
// looks to be an object, it points to a valid class pointer
and (p^ = PPointer(PByte(p^) + vmtSelfPtr)^) then
Result := True;
except
end; //FI:W501
end;
我们可以这样使用这个函数:
var
o: TObject;
p: Pointer;
i: NativeInt;
begin
i := 5;
p := @i;
o := TObject.Create;
Writeln(IsValidObject(Pointer(o))); // TRUE
Writeln(IsValidObject(p)); // FALSE
end.
1条答案
按热度按时间yebdmbv41#
没有安全的方法来确定有效指针是否为
TObject
引用您只能确定地判断指针不是对象引用。
话虽如此,出于调试目的,有一种方法可以检测指针可能是对象引用,但您也可能得到误报-我们正在检查的内存内容可能完全偶然地满足检查。
每个对象示例还拥有一个指向其类虚方法表的指针- VMT。它还拥有一个指向其数据开始的指针-该指针的偏移量由
System
单元中声明的vmtSelfPtr
常量定义。vmtSelfPtr
中的类引用与对象不同,因为它们将引用保留回自身。上面的事实将告诉我们我们不是先在看一个类引用,然后我们将检查可能对象的VMT是否指向可能的类引用。
除此之外,对于每个指针,我们将首先检查它是否属于有效的地址空间。
您可以在此处找到有关VMT的更多信息内部数据格式-类类型
检测指针是否为可能对象的代码取自Spring 4D库:
我们可以这样使用这个函数:
注意:
IsValidObject
只能用于有效的指针-即指向有效分配内存的指针。您无法检测指针后面的对象示例是否已被释放。如果您有下列程式码,您仍然会取得
TRUE
做为IsValidObject
呼叫的结果。**注意:**除了用于调试目的之外,在发布模式下,可以在您知道是
nil
、类引用或对象引用的任何指针上安全地调用IsValidObject
。换句话说,您可以安全地使用它来区分类引用和对象引用。