gpt4 book ai didi

delphi - 我得到 RTTIMethod.Visibility = mvPublic 作为私有(private)记录方法。 - 漏洞?

转载 作者:行者123 更新时间:2023-12-03 15:13:30 27 4
gpt4 key购买 nike

我使用 Delphi 10.2 得到(严格)私有(private)记录方法的 RTTIMethod.Visibility = mvPublic。这是一个错误吗?

<小时/>

更新 2017-07-12:已创建问题:RSP-18587 .

<小时/>

程序输出显示记录和类的所有实例成员类型和可见性;从 RTTI 返回的可见性;看看 TSomeRec 中的 PrivateProcedure:

Types:
Unit1.TSomeRec
Fields:
PrivateField
Visibility: mvPrivate
PublicField
Visibility: mvPublic
Properties:
Methods:
PrivateProcedure
Visibility: mvPublic
PrivateFunction
Visibility: mvPublic
PublicProcedure
Visibility: mvPublic
PublicFunction
Visibility: mvPublic
Unit1.TSomeClass
Fields:
PrivateField
Visibility: mvPrivate
ProtectedField
Visibility: mvProtected
PublicField
Visibility: mvPublic
Properties:
PrivateProperty
Visibility: mvPrivate
ProtectedProperty
Visibility: mvProtected
PublicProperty
Visibility: mvPublic
PublishedProperty
Visibility: mvPublished
Methods:
PrivateProcedure
Visibility: mvPrivate
PrivateFunction
Visibility: mvPrivate
ProtectedProcedure
Visibility: mvProtected
ProtectedFunction
Visibility: mvProtected
PublicProcedure
Visibility: mvPublic
PublicFunction
Visibility: mvPublic
PublishedProcedure
Visibility: mvPublished
PublishedFunction
Visibility: mvPublished
<小时/>

Unit1.pas:

unit Unit1;

interface

{$RTTI explicit
Methods ([vcPrivate, vcProtected, vcPublic, vcPublished])
Properties ([vcPrivate, vcProtected, vcPublic, vcPublished])
Fields ([vcPrivate, vcProtected, vcPublic, vcPublished])
}

{$Region 'TSomeRec'}

type
TSomeRec = record
strict private
PrivateField: Boolean;
property PrivateProperty: Boolean read PrivateField;
procedure PrivateProcedure;
function PrivateFunction: Boolean;

public
PublicField: Boolean;
property PublicProperty: Boolean read PublicField;
procedure PublicProcedure;
function PublicFunction: Boolean;
end;

{$EndRegion}
{$Region 'TSomeClass'}

type
TSomeClass = class
strict private
PrivateField: Boolean;
property PrivateProperty: Boolean read PrivateField;
procedure PrivateProcedure;
function PrivateFunction: Boolean;

strict protected
ProtectedField: Boolean;
property ProtectedProperty: Boolean read ProtectedField;
procedure ProtectedProcedure;
function ProtectedFunction: Boolean;

public
PublicField: Boolean;
property PublicProperty: Boolean read PublicField;
procedure PublicProcedure;
function PublicFunction: Boolean;

published
property PublishedProperty: Boolean read PublicField;
procedure PublishedProcedure;
function PublishedFunction: Boolean;
end;

{$EndRegion}

implementation

{$Region 'TSomeRec'}

{ TSomeRec }

function TSomeRec.PrivateFunction: Boolean;
begin
Result := False;
end;

procedure TSomeRec.PrivateProcedure;
begin
end;

function TSomeRec.PublicFunction: Boolean;
begin
Result := False;
end;

procedure TSomeRec.PublicProcedure;
begin
end;

{$EndRegion}
{$Region 'TSomeClass'}

{ TSomeClass }

function TSomeClass.PrivateFunction: Boolean;
begin
Result := False;
end;

procedure TSomeClass.PrivateProcedure;
begin
end;

function TSomeClass.ProtectedFunction: Boolean;
begin
Result := False;
end;

procedure TSomeClass.ProtectedProcedure;
begin
end;

function TSomeClass.PublicFunction: Boolean;
begin
Result := False;
end;

procedure TSomeClass.PublicProcedure;
begin
end;

function TSomeClass.PublishedFunction: Boolean;
begin
Result := False;
end;

procedure TSomeClass.PublishedProcedure;
begin
end;

{$EndRegion}

end.

Project1.dpr:

program Project1;

{$AppType Console}

{$R *.res}

uses
System.RTTI,
System.StrUtils,
System.SysUtils,
System.TypInfo,
Unit1 in 'Unit1.pas';

{$Region 'IWriter, TWriter'}

type
IWriter = interface
procedure BeginSection(const Value: String = '');
procedure EndSection;
procedure WriteMemberSection(const Value: TRTTIMember);
end;

TWriter = class (TInterfacedObject, IWriter)
strict private
FIndentCount: NativeInt;

strict protected
procedure BeginSection(const Value: String);
procedure EndSection;
procedure WriteLn(const Value: String);
procedure WriteMemberSection(const Value: TRTTIMember);

public
const
IndentStr = ' ';
end;

{ TWriter }

procedure TWriter.BeginSection(const Value: String);
begin
WriteLn(Value);
Inc(FIndentCount);
end;

procedure TWriter.EndSection;
begin
Dec(FIndentCount);
end;

procedure TWriter.WriteLn(const Value: String);
begin
System.WriteLn(DupeString(IndentStr, FIndentCount) + Value);
end;

procedure TWriter.WriteMemberSection(const Value: TRTTIMember);
begin
BeginSection(Value.Name);
try
WriteLn('Visibility: ' + TValue.From<TMemberVisibility>(Value.Visibility).ToString);
finally
EndSection;
end;
end;

{$EndRegion}

{$Region '...'}

procedure Run;
var
Writer: IWriter;
RTTIContext: TRTTIContext;
RTTIType: TRTTIType;
RTTIField: TRTTIField;
RTTIProp: TRTTIProperty;
RTTIMethod: TRTTIMethod;
begin
Writer := TWriter.Create;
RTTIContext := TRTTIContext.Create;
try
RTTIContext.GetType(TypeInfo(TSomeRec));
RTTIContext.GetType(TypeInfo(TSomeClass));
Writer.BeginSection('Types:');
for RTTIType in RTTIContext.GetTypes do
begin
if not RTTIType.Name.Contains('ISome')
and not RTTIType.Name.Contains('TSome') then
Continue;
Writer.BeginSection(RTTIType.QualifiedName);
Writer.BeginSection('Fields:');
for RTTIField in RTTIType.GetFields do
begin
if not RTTIField.Name.EndsWith('Field') then
Continue;
Writer.WriteMemberSection(RTTIField);
end;
Writer.EndSection;
Writer.BeginSection('Properties:');
for RTTIProp in RTTIType.GetProperties do
begin
if not RTTIProp.Name.EndsWith('Property') then
Continue;
Writer.WriteMemberSection(RTTIProp);
end;
Writer.EndSection;
Writer.BeginSection('Methods:');
for RTTIMethod in RTTIType.GetMethods do
begin
if not RTTIMethod.Name.Contains('Procedure')
and not RTTIMethod.Name.Contains('Function') then
Continue;
Writer.WriteMemberSection(RTTIMethod);
end;
Writer.EndSection;
Writer.EndSection;
end;
Writer.EndSection;
finally
RTTIContext.Free;
end;
end;

{$EndRegion}

begin
{$Region '...'}
try
Run;
except
on E: Exception do
WriteLn(E.ClassName, ': ', E.Message);
end;
ReadLn;
{$EndRegion}
end.

最佳答案

该错误是 TRttiRecordMethod 中未覆盖 GetVisibility。我查看了一些代码,有关可见性的信息实际上位于 Flag 字段内。

与其他 GetVisibility 覆盖(例如 TRttiRecordField 中的覆盖)类似,它需要实现。我将此报告为 RSP-18588 .

我写了一个小补丁,如果你确实需要修复这个问题(仅限 Windows),应该可以修复这个问题。

unit PatchRecordMethodGetVisibility;

interface

implementation

uses
Rtti, SysUtils, TypInfo, Windows;

type
TRec = record
procedure Method;
end;

procedure TRec.Method;
begin
end;

function GetVirtualMethod(AClass: TClass; const Index: Integer): Pointer;
begin
Result := PPointer(UINT_PTR(AClass) + UINT_PTR(Index * SizeOf(Pointer)))^;
end;

procedure RedirectFunction(OrgProc, NewProc: Pointer);
type
TJmpBuffer = packed record
Jmp: Byte;
Offset: Integer;
end;
var
n: UINT_PTR;
JmpBuffer: TJmpBuffer;
begin
JmpBuffer.Jmp := $E9;
JmpBuffer.Offset := PByte(NewProc) - (PByte(OrgProc) + 5);
if not WriteProcessMemory(GetCurrentProcess, OrgProc, @JmpBuffer, SizeOf(JmpBuffer), n) then
RaiseLastOSError;
end;

type
TRttiRecordMethodFix = class(TRttiMethod)
function GetVisibility: TMemberVisibility;
end;

procedure PatchIt;
var
ctx: TRttiContext;
recMethodCls: TClass;
begin
recMethodCls := ctx.GetType(TypeInfo(TRec)).GetMethod('Method').ClassType;
RedirectFunction(GetVirtualMethod(recMethodCls, 3), @TRttiRecordMethodFix.GetVisibility);
end;

{ TRttiRecordMethodFix }

function TRttiRecordMethodFix.GetVisibility: TMemberVisibility;

function GetBitField(Value, Shift, Bits: Integer): Integer;
begin
Result := (Value shr Shift) and ((1 shl Bits) - 1);
end;

const
rmfVisibilityShift = 2;
rmfVisibilityBits = 2;
begin
Result := TMemberVisibility(GetBitField(PRecordTypeMethod(Handle)^.Flags, rmfVisibilityShift, rmfVisibilityBits))
end;

initialization
PatchIt;

end.

关于delphi - 我得到 RTTIMethod.Visibility = mvPublic 作为私有(private)记录方法。 - 漏洞?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45040739/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com