Skip to content

Rtti.Invoke is not working correctly on Linux using ffi.manager

I created a small test for Rtti.Invoke and it worked successfully on Windows, however, there were problems in the implementation of ffi.manager. Test code:

program RttiInvokeTest;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}
  cthreads,
  {$ENDIF}
  Classes,
  TypInfo,
  Rtti
  {$ifndef Windows}
  , ffi.manager
  {$endif};

type
  TMyClass=class
    public
      MyField: integer;
  end;

  TTestClass=class
    public
      Info: string;
      function TestAll(arg1: TPoint; arg2: TRect; arg3: TMyClass; arg4: Integer; arg5: Pointer; arg6: Double; arg7: Boolean; arg8: string): TPoint;
  end;

function TTestClass.TestAll(arg1: TPoint; arg2: TRect; arg3: TMyClass; arg4: Integer; arg5: Pointer; arg6: Double; arg7: Boolean; arg8: string): TPoint;
begin
  WriteLn('Self Info: ', Self.Info);
  WriteLn('getted Point(', arg1.X, ', ', arg1.Y, ')');
  WriteLn('getted Rect(', arg2.Left, ', ', arg2.Top, ', ', arg2.Right, ', ', arg2.Bottom, ')');
  WriteLn('my class field: ', arg3.MyField);
  WriteLn('integer: ', arg4);     
  WriteLn('my class (by pointer) field: ', TMyClass(arg5).MyField);
  WriteLn('double: ', arg6:0:5);
  WriteLn('boolean: ', arg7);  
  WriteLn('string: ', arg8);

  Result := Point(1111, 2222);
end;

var
  p, pnt_arg: Pointer;
  point, pnt_ret: TPoint;
  rect: TRect;
  myClass: TMyClass;
  int: Integer;
  dbl: Double;
  bln: Boolean;
  str: string;
  testClass: TTestClass;

  val1, val2, val3, val5, val_self, val_ret: TValue;
begin
  p := @TTestClass.TestAll;

  point := TPoint.Create(123, 456);
  rect := TRect.Create(12, 34, 56, 78);  

  myClass := TMyClass.Create;
  myClass.MyField:=123456;

  pnt_arg := Pointer(myClass);

  TValue.Make(@point, TypeInfo(TPoint), val1);
  TValue.Make(@rect, TypeInfo(TRect), val2);
  TValue.Make(@myClass, TypeInfo(TMyClass), val3);
  TValue.Make(@pnt_arg, TypeInfo(Pointer), val5);

  int := 3456789;
  dbl := 9876.54321;
  bln := True;
  str := 'simple str';

  testClass := TTestClass.Create;
  testClass.Info:='TestClass Information';
  TValue.Make(@testClass, TypeInfo(TTestClass), val_self);

  val_ret := Rtti.Invoke(p, [val_self, val1, val2, val3, int, val5, dbl, bln, str], ccReg, TypeInfo(TPoint), False, False);
  pnt_ret := TPoint(val_ret.GetReferenceToRawData^);
  WriteLn('returned Point(', pnt_ret.X, ', ', pnt_ret.Y, ')');

  ReadLn;
end.

Incorrect output on Linux:

Self Info: TestClass Information
getted Point(123, 0)
getted Rect(12, 34, 56, 0)
my class field: 123456
integer: 3456789
my class (by pointer) field: 123456
double: 9876.54321
boolean: TRUE
string: simple str
returned Point(1111, 0)

Output on Windows (x64), consistent with the expected output:

Self Info: TestClass Information
getted Point(123, 456)
getted Rect(12, 34, 56, 78)
my class field: 123456
integer: 3456789
my class (by pointer) field: 123456
double: 9876.54321
boolean: TRUE
string: simple str
returned Point(1111, 2222)
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information