santiagoIT
santiagoIT

Reputation: 9431

Reading TValue from TRttiProperty fails (Property Type: set of Byte)

I defined a type for set of Byte, an interface and a class that implements the interface. The interface has a property of type TTestSetofByte + getter and setter. Nothing special at all.

type
 TTestSetOfByte = set of Byte;
  ITestInterface = interface
    ['{BCF0CEC2-F999-4E8A-A732-416F343C1629}']
    function GetPropSetOfByte: TTestSetOfByte;
    procedure SetPropSetOfByte(const Value: TTestSetOfByte);
    property PropSetOfByte: TTestSetOfByte read GetPropSetOfByte write SetPropSetOfByte;
  end;

  TTestClass3 = class(TInterfacedObject, ITestInterface)
  private
    FSetOfByte: TTestSetOfByte;
    function GetPropSetOfByte: TTestSetOfByte;
    procedure SetPropSetOfByte(const Value: TTestSetOfByte);
  public
    constructor Create;
    property PropSetOfByte: TTestSetOfByte read GetPropSetOfByte write SetPropSetOfByte;
  end;

The problem is that when I try to read the Value of the PropSetOfByte property delphi throws an EAccessViolation and I do not understand why. Properties of other types(int, string) work just fine.

Here is the test code:

procedure TTestUtlRttiComparer.DeleteMe;
var
  i: Integer;
  Instance1: ITestInterface;
  Object1: TObject;
  RttiContext: TRttiContext;
  RttiProp: TRttiProperty;
  RttiValue1: TValue;
  Type1: TRttiType;
begin
  Instance1 := TTestClass3.Create;
  Check(Instance1.PropSetOfByte = [1,4], 'Making sure getter works!');
  Instance1.PropSetOfByte := [3,4];
  Check(Instance1.PropSetOfByte = [3,4], 'Making sure setter works!');

  Object1 := (Instance1 as TObject);
  Check(Assigned(Object1));

  RttiContext := TRttiContext.Create;
  try
    Type1 := RttiContext.GetType(Object1.ClassInfo);

    // Properties pruefen
    for i := 0 to High(Type1.GetProperties) do
    begin
      RttiProp :=  Type1.GetProperties[i];
      if RttiProp.Name = 'PropSetOfByte' then
      begin
        RttiValue1 := RttiProp.GetValue(Object1); // THIS CHECK FAILS with EACESSVIOLATION!!!
      end;
    end;
  finally
    RttiContext.Free;
  end;
end;

I am using XE-2.

Thank you!

Upvotes: 0

Views: 1224

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598309

It crashes when TRttiType.GetValue() (more specifically, the Invoke() function in the System.Rtti unit) tries to call TTestClass3.GetPropSetOfByte(). The correct Self pointer is being passed in, but the Result parameter is nil, so a crash occurs when GetPropSetOfByte() tries to assign FSetOfByte to Result.

In short, the call stack is not being setup correctly by the RTTI system for Set-based properties. I have reproduced the crash in XE2, XE6, and XE7, and have filed a bug report with Embarcadero:

TRttiProperty.GetValue() crash on Set-based property https://quality.embarcadero.com/browse/RSP-10206

Upvotes: 3

Related Questions