- edited description
Event<T> passes wrong parameter to handler when T is ...
Consider the following snippet:
program Project1;
uses System.SysUtils, Spring;
type
{$M+}
THandlerProc<T> = reference to procedure(const eventArgs: T);
{$M-}
TData = record
bool1, bool2, bool3: Boolean;
class operator Equal(const a, b: TData): Boolean;
end;
var
sent, received: TData;
class operator TData.Equal(const a, b: TData): Boolean;
begin
Result := (a.bool1 = b.bool1) and (a.bool2 = b.bool2) and (a.bool3 = b.bool3);
end;
procedure handleEvent(const eventArgs: TData);
begin
received := eventArgs;
end;
procedure p();
var
myEvent: Spring.Event<THandlerProc<TData>>;
begin
myEvent.Add(handleEvent);
sent.bool1 := False;
sent.bool2 := True;
sent.bool3 := False;
myEvent.Invoke(sent);
Assert( sent = received );
end;
begin
p();
end.
You would expect the assertion to succeed. handleEvent(..) should be called with a record of (False, True, False). However, the passed record has all fields set to false and the assertion fails.
What really confuses me is that the assertion does not fail when TData has four or just two booleans. I have absolutely no clue why this is the case as I am unable to understand and debug the assembler code.
Comments (11)
-
reporter -
reporter - edited description
-
repo owner - changed status to open
Looks to be a bug in System.Rtti as this also happens when doing TRttiMethod.Invoke - I will investigate.
-
repo owner -
assigned issue to
-
assigned issue to
-
reporter In case it helps, my Delphi version was “10 Seattle Subscription Update 1”.
Build was Win32. Win64 appears to work fine. -
repo owner Seems to be records of size 3 are being passed wrong. I am gonna prepare a repro and report it to QP later. You probably have to put a dummy field to make the record size 4 for being passed properly as I can’t do anything about it.
-
reporter Yes, that’s what I did. Thanks for taking the time to investigate. Does this affect all of Event<T> with T being TAction<X> and SizeOf(X) = 3? Not sure if it makes sense to make run-time checks and raise an exception…
-
repo owner It potentially affects all places that use Rtti Invoke passing such a parameter. And I will not put any mitigation code for RTL bugs. When I got no other things to do I could look if I can patch the defect code similar to other runtime patches that come with Spring4D but it’s probably more of a waste of time that could better be spent elsewhere.
-
repo owner - changed milestone to 2.0
After a more thorough look I found out the issue is in Spring.Events where 3 byte types are treated as passed via register which they surprisingly are not but pushed on the stack. I will fix this.
-
repo owner - changed status to resolved
fixed
#327→ <<cset fa1de70a141a>>
-
repo owner fixed
#327→ <<cset 0f48166be60f>>
- Log in to comment