dmitrybv 3 Posted Monday at 11:08 PM Hello I can't figure out why the following code causes an AV error. procedure TFormSimpleDraw2.Button2Click(Sender: TObject); var Value: TValue; LType: TRttiType; RttiContext: TRttiContext; CaretPositionProp: TRttiProperty; CaretPosition: TCaretPosition; begin RttiContext := TRttiContext.Create; LType := RttiContext.GetType(Memo1.ClassInfo); CaretPosition := Memo1.CaretPosition; CaretPositionProp := LType.GetProperty('CaretPosition'); Value := CaretPositionProp.GetValue(Memo1); //AV is here end; Embarcadero® RAD Studio 12 Version 29.0.55362.2017 1. Create FMX Form. 2. Put TButton and TMemo on the Form. 3. Write TButton.OnClick as written above 4. Run and click Button Share this post Link to post
Remy Lebeau 1597 Posted Tuesday at 02:57 AM You are not checking if either TRttiContext.GetType() or TRttiType.GetProperty() are returning nil before accessing the objects they return. procedure TFormSimpleDraw2.Button2Click(Sender: TObject); var Value: TValue; LType: TRttiType; RttiContext: TRttiContext; CaretPositionProp: TRttiProperty; CaretPosition: TCaretPosition; begin RttiContext := TRttiContext.Create; LType := RttiContext.GetType(Memo1.ClassInfo); if LType = nil then Exit; // <-- add this CaretPosition := Memo1.CaretPosition; CaretPositionProp := LType.GetProperty('CaretPosition'); if CaretPositionProp = nil then Exit; // <-- add this Value := CaretPositionProp.GetValue(Memo1); ... end; Share this post Link to post
Lajos Juhász 319 Posted Tuesday at 06:44 AM (edited) CaretPositionProp is not nil, however when invoking the GetValyue in CaretPositionProp.GetValue self is an Inaccessible value: FMX.Memo.TCustomMemo.GetCaretPosition :00cfcac8 RawInvoke + $40 System.Rtti.RawInvoke(???,???) :00cfcead Invoke + $249 System.Rtti.Invoke(nil,(),???,???,True,True) :00cf5689 TRttiInstanceProperty.DoGetValue + $DD System.Rtti.TRttiInstanceProperty.DoGetValue(???) :00cf54ae TRttiProperty.GetValue + $26 Since it is pointing to an invalid address the Access Violation is when the code tries to execute Model.CaretPosition. Edited Tuesday at 06:46 AM by Lajos Juhász Share this post Link to post
dmitrybv 3 Posted yesterday at 01:03 AM If this issue is related to a bug in RTTI or TMemo, then a new bug report should be added to the Embarcadero Quality Portal. If this issue is related to the fact that the CaretPosition property cannot be read via RTTI, then is there a way to check this. Share this post Link to post
Stefan Glienke 2141 Posted yesterday at 05:51 AM (edited) Okay, the reason is because the CaretPosition getter is declared as cdecl (I have no clue why that is the case - I would assume some C++ compat because the result is a record) and the code for getting properties does not know about the calling conventions of their setter and getter (because that is not part of their RTTI but only the code pointer to them) and thus always assumes standard calling convention. Edited yesterday at 05:53 AM by Stefan Glienke 1 Share this post Link to post
Remy Lebeau 1597 Posted 17 hours ago (edited) 10 hours ago, Stefan Glienke said: the code for getting properties does not know about the calling conventions of their setter and getter (because that is not part of their RTTI but only the code pointer to them) and thus always assumes standard calling convention. Actually, calling convention is part of the RTTI for invokable types, including class methods. But TRttiInstanceProperty.DoGetValue() (and DoSetValue()) are ignoring that fact and just assume Delphi's default Register convention when invoking the property getter/setter. If I change the invocation to specify Cdecl instead of Register, then no crash occurs. I have opened a bug ticket for this: RSS-3574: AV in TRttiProperty if getter/setter does not use Register calling convention Edited 16 hours ago by Remy Lebeau Share this post Link to post
dmitrybv 3 Posted 9 hours ago "Just curious — how did you specify the calling convention cdecl? After all, DoGetValue doesn't contain any parameters for specifying the calling convention." Share this post Link to post
Remy Lebeau 1597 Posted 9 hours ago (edited) 42 minutes ago, dmitrybv said: "Just curious — how did you specify the calling convention cdecl? After all, DoGetValue doesn't contain any parameters for specifying the calling convention." I simply used the debugger at runtime to modify the CallingConvention parameter of the internal System.Rtti.Invoke() function that DoGetValue() calls for a getter method. DoGetValue() is hard-coded to pass in a value of ccReg, I just changed that to ccCdecl instead, and then the AV went away. That is at least a POC that the issue could be fixed if DoGetValue() were made to be more sensitive to the getter's actual RTTI. And likewise for DoSetValue(), too. Edited 8 hours ago by Remy Lebeau 1 Share this post Link to post