Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / lazarus / 2018-02

OI / App crash - components with published interfaces

4 messages · 2 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Andreas Frieß

I have an appcrash when i use components with interfaces in the published part. See also Bug 32919. I have now simpilied the problem and isolated from Lazarus itself.

The component is on https://github.com/afriess/LazarusBug0032919 in OITestBasic, together with the testproject shown here.

Somethigs goes wrong , if call free for the Form ( SIGSEGV ). A sencond issue is, i did not see the value of the property ObjectHasInterface in the OI.  But i see the value if i click on the Combobox.

My Question:

Did i miss something in the definition of the Components ?

------------ definition components ---------------

type
   // define the Interface
   ITestInterface =  interface
       function OnlyDummy: integer;
     end;
   { TIntfComp }
   TIntfComp = class(TComponent)
   private
     FObjectHasInterface: ITestInterface;
     function GetObjectHasInterface: ITestInterface;
     procedure SetObjectHasInterface(AValue: ITestInterface);
   published
     property ObjectHasInterface: ITestInterface read
GetObjectHasInterface write SetObjectHasInterface;
   end;

  { TCompHasIntf }
  TCompHasIntf = class(TComponent, ITestInterface)   public
    function OnlyDummy: integer;
  end;

--------- test programm ------------

     DUT := TObjectInspectorDlg.Create(nil);
     DUT.Caption:= 'My ObjectInspector';
     // create the PropertyEditorHook (the interface to the properties)
     ThePropertyEditorHook:=TPropertyEditorHook.Create(DUT);
     DUT.PropertyEditorHook:=ThePropertyEditorHook;
     // Create components
     ATestForm :=  TForm.Create(nil);
     ATestForm.Name:= 'Main';
     ATestIntf := TIntfComp.Create(ATestForm);       // This componnets
can hold a component with interface
     ATestIntf.Name := 'ATestIntf';
     ATestHasIntf := TCompHasIntf.Create(ATestForm); // This component
has an Interface
     ATestHasIntf.Name:= 'ATestHasIntf';
     ATestIntf.ObjectHasInterface := ATestHasIntf;
     ATestIntf.GetParentComponent;
     ThePropertyEditorHook.LookupRoot:=ATestForm;
     PerList:=TPersistentSelectionList.Create;
     PerList.Add(ATestForm);
     DUT.Selection:=PerList;
     PerList.Free;
     DUT.Show;

.......

   if DUT  nil then begin
     ATestForm.Free;   // <----- Appcrash
     FreeAndNil(DUT);
   end;
----------------------- End ------------------

------------------ Stack ------------------------

#0 fpc_intf_decr_ref at :0
#1 fpc_finalize at :0
#2 ?? at :0
#3 SYSTEM_$$_SETVARIANTMANAGER$TVARIANTMANAGER at :0 #4 ?? at :0
#5 DESTROY(0x3aa8868, 0x0) at include\control.inc:5146 #6 DESTROY(0x3aa8868, 0x0) at include\wincontrol.inc:6626 #7 DESTROY(0x3aa8868, 0x0) at include\customcontrol.inc:40 #8 DESTROY(0x3aa8868, 0x0) at include\scrollingwincontrol.inc:316 #9 DESTROY(0x3aa8868, 0x1) at include\customform.inc:212 #10 SYSTEM$_$TOBJECT_$__$$_FREE at :0
#11 FREEUSEDOBJECTS(0x3ad46f8) at uoitest.pas:161
#12 BUFREECLICK(0x3ad46f8, 0x3ad5878) at uoitest.pas:139 #13 CLICK(0x3ad5878) at include\control.inc:2929
#14 CLICK(0x3ad5878) at include\buttoncontrol.inc:55 #15 CLICK(0x3ad5878) at include\buttons.inc:169
#16 WMDEFAULTCLICKED(0x3ad5878, {MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\buttoncontrol.inc:21 #17 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal at :0
#18 ?? at :0
#19 VMT_$STDCTRLS_$$_TBUTTONCONTROL at :0
#20 VMT_$STDCTRLS_$$_TCUSTOMSTATICTEXT$indirect at :0 #21 STDCTRLS$_$TBUTTONCONTROL_$__$$_ISCHECKEDSTORED$$BOOLEAN at :0 #22 WNDPROC(0x3ad5878, {MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\wincontrol.inc:5406
#23 DELIVERMESSAGE(0x3ad5878, 0) at lclmessageglue.pas:112 #24 DOWINDOWPROC(0x3b0d780) at win32\win32callback.inc:2534 #25 WINDOWPROC(199064, 273, 22648, 1705918) at win32\win32callback.inc:2696 #26 CUSTOMFORMWNDPROC(199064, 273, 22648, 1705918) at win32\win32wsforms.pp:386
#27 USER32!AddClipboardFormatListener at :0
#28 USER32!EndTask at :0
#29 DEBUGSTART_$WIN32WSFORMS at :0
#30 USER32!EndTask at :0
#31 ?? at :0
#32 USER32!EndTask at :0
#33 DEBUGSTART_$WIN32WSFORMS at :0
#34 USER32!SendMessageW at :0
#35 CreateMappedBitmap at :0
#36 ImageList_GetIconSize at :0
#37 USER32!AddClipboardFormatListener at :0
#38 USER32!EndTask at :0
#39 ImageList_GetIconSize at :0
#40 USER32!EndTask at :0
#41 ?? at :0
#42 USER32!EndTask at :0
#43 ImageList_GetIconSize at :0
#44 USER32!CallWindowProcW at :0
#45 CALLDEFAULTWINDOWPROC(1705918, 514, 0, 1310774) at win32\win32callback.inc:97
#46 DOWINDOWPROC(0x3b0d610) at win32\win32callback.inc:2442 #47 WINDOWPROC(1705918, 514, 0, 1310774) at win32\win32callback.inc:2696 #48 BUTTONWNDPROC(1705918, 514, 0, 1310774) at win32\win32wsstdctrls.pp:1791 #49 USER32!AddClipboardFormatListener at :0
#50 USER32!EndTask at :0
#51
WIN32WSSTDCTRLS$_$TWIN32WSBUTTONCONTROL_$__$$_GETPREFERREDSIZE$TWINCONTROL$LONGINT$LONGINT$BOOLEAN at :0
#52 USER32!EndTask at :0
#53 ?? at :0
#54 USER32!DispatchMessageW at :0
#55 USER32!DispatchMessageW at :0
#56 APPPROCESSMESSAGES(0x3af7fd0) at win32\win32object.inc:407 #57 HANDLEMESSAGE(0x3a98408) at include\application.inc:1276 #58 RUNLOOP(0x3a98408) at include\application.inc:1413 #59 APPRUN(0x3af7fd0, {Proc = {procedure (POINTER)} 0x177ff48, Self = 0x3a98408}) at include\interfacebase.inc:54
#60 RUN(0x3a98408) at include\application.inc:1401 #61 :19
------------------- End Stack ---------------------------

Reply by email

Andreas Frieß
to Andreas Frieß
Now i have inserted code in the TIntfComp to remove the link to the
interface

--------------------

destructor TIntfComp.Destroy;
begin
   FObjectHasInterface := nil;  // <<-- Crahe here now
   inherited Destroy;
end;
--------------------

And now i it crash explicitly  at the line wher i try to 'unlink'. And the Callstack from Lazarus give me some information. The setting to nil, call fpc_intf_assign and  call IUnknown(D)._Release. But this is absolutly unwated (and unexpected) for me here.

How can i release the link without calling  fpc_intf_assign. Or what is my mistake of understanding ?

Andreas

-------------------------------

#0 fpc_intf_assign at :0
#1 DESTROY(0x3868750, 0x1) at intfcomp.pas:76
#2 CLASSES$_$TCOMPONENT_$__$$_DESTROYCOMPONENTS at :0 #3 CLASSES$_$TCOMPONENT_$__$$_DESTROY at :0
#4 ?? at :0
#5 DESTROY(0x3838d38, 0x0) at include\control.inc:5146 #6 DESTROY(0x3838d38, 0x0) at include\wincontrol.inc:6626 #7 DESTROY(0x3838d38, 0x0) at include\customcontrol.inc:40 #8 DESTROY(0x3838d38, 0x0) at include\scrollingwincontrol.inc:316 #9 DESTROY(0x3838d38, 0x1) at include\customform.inc:212 #10 SYSTEM$_$TOBJECT_$__$$_FREE at :0
#11 FREEUSEDOBJECTS(0x38648d8) at uoitest.pas:161
#12 BUFREECLICK(0x38648d8, 0x3865a58) at uoitest.pas:139 ---------------------------

Andreas Frieß wrote 160 lines
I have an appcrash when i use components with interfaces in the published part. See also Bug 32919. I have now simpilied the problem and isolated from Lazarus itself. The component is on https://github.com/afriess/LazarusBug0032919 in OITestBasic, together with the testproject shown here. Somethigs goes wrong , if call free for the Form ( SIGSEGV ). A sencond issue is, i did not see the value of the property ObjectHasInterface in the OI.  But i see the value if i click on the Combobox. My Question: Did i miss something in the definition of the Components ? ------------ definition components --------------- type   // define the Interface   ITestInterface =  interface       function OnlyDummy: integer;     end;   { TIntfComp }   TIntfComp = class(TComponent)   private     FObjectHasInterface: ITestInterface;     function GetObjectHasInterface: ITestInterface;     procedure SetObjectHasInterface(AValue: ITestInterface);   published     property ObjectHasInterface: ITestInterface read GetObjectHasInterface write SetObjectHasInterface;   end;   { TCompHasIntf }   TCompHasIntf = class(TComponent, ITestInterface)   public     function OnlyDummy: integer;   end; --------- test programm ------------     DUT := TObjectInspectorDlg.Create(nil);     DUT.Caption:= 'My ObjectInspector';     // create the PropertyEditorHook (the interface to the properties)     ThePropertyEditorHook:=TPropertyEditorHook.Create(DUT);     DUT.PropertyEditorHook:=ThePropertyEditorHook;     // Create components     ATestForm :=  TForm.Create(nil);     ATestForm.Name:= 'Main';     ATestIntf := TIntfComp.Create(ATestForm);       // This componnets can hold a component with interface     ATestIntf.Name := 'ATestIntf';     ATestHasIntf := TCompHasIntf.Create(ATestForm); // This component has an Interface     ATestHasIntf.Name:= 'ATestHasIntf';     ATestIntf.ObjectHasInterface := ATestHasIntf;     ATestIntf.GetParentComponent;     ThePropertyEditorHook.LookupRoot:=ATestForm;     PerList:=TPersistentSelectionList.Create;     PerList.Add(ATestForm);     DUT.Selection:=PerList;     PerList.Free;     DUT.Show; .......   if DUT nil then begin     ATestForm.Free;   // <----- Appcrash     FreeAndNil(DUT);   end; ----------------------- End ------------------ ------------------ Stack ------------------------ #0 fpc_intf_decr_ref at :0 #1 fpc_finalize at :0 #2 ?? at :0 #3 SYSTEM_$$_SETVARIANTMANAGER$TVARIANTMANAGER at :0 #4 ?? at :0 #5 DESTROY(0x3aa8868, 0x0) at include\control.inc:5146 #6 DESTROY(0x3aa8868, 0x0) at include\wincontrol.inc:6626 #7 DESTROY(0x3aa8868, 0x0) at include\customcontrol.inc:40 #8 DESTROY(0x3aa8868, 0x0) at include\scrollingwincontrol.inc:316 #9 DESTROY(0x3aa8868, 0x1) at include\customform.inc:212 #10 SYSTEM$_$TOBJECT_$__$$_FREE at :0 #11 FREEUSEDOBJECTS(0x3ad46f8) at uoitest.pas:161 #12 BUFREECLICK(0x3ad46f8, 0x3ad5878) at uoitest.pas:139 #13 CLICK(0x3ad5878) at include\control.inc:2929 #14 CLICK(0x3ad5878) at include\buttoncontrol.inc:55 #15 CLICK(0x3ad5878) at include\buttons.inc:169 #16 WMDEFAULTCLICKED(0x3ad5878, {MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\buttoncontrol.inc:21 #17 SYSTEM$_$TOBJECT_$__$$_DISPATCH$formal at :0 #18 ?? at :0 #19 VMT_$STDCTRLS_$$_TBUTTONCONTROL at :0 #20 VMT_$STDCTRLS_$$_TCUSTOMSTATICTEXT$indirect at :0 #21 STDCTRLS$_$TBUTTONCONTROL_$__$$_ISCHECKEDSTORED$$BOOLEAN at :0 #22 WNDPROC(0x3ad5878, {MSG = 66567, WPARAM = 0, LPARAM = 0, RESULT = 0, WPARAMLO = 0, WPARAMHI = 0, WPARAMFILLER = {}, LPARAMLO = 0, LPARAMHI = 0, LPARAMFILLER = {}, RESULTLO = 0, RESULTHI = 0, RESULTFILLER = {}}) at include\wincontrol.inc:5406 #23 DELIVERMESSAGE(0x3ad5878, 0) at lclmessageglue.pas:112 #24 DOWINDOWPROC(0x3b0d780) at win32\win32callback.inc:2534 #25 WINDOWPROC(199064, 273, 22648, 1705918) at win32\win32callback.inc:2696 #26 CUSTOMFORMWNDPROC(199064, 273, 22648, 1705918) at win32\win32wsforms.pp:386 #27 USER32!AddClipboardFormatListener at :0 #28 USER32!EndTask at :0 #29 DEBUGSTART_$WIN32WSFORMS at :0 #30 USER32!EndTask at :0 #31 ?? at :0 #32 USER32!EndTask at :0 #33 DEBUGSTART_$WIN32WSFORMS at :0 #34 USER32!SendMessageW at :0 #35 CreateMappedBitmap at :0 #36 ImageList_GetIconSize at :0 #37 USER32!AddClipboardFormatListener at :0 #38 USER32!EndTask at :0 #39 ImageList_GetIconSize at :0 #40 USER32!EndTask at :0 #41 ?? at :0 #42 USER32!EndTask at :0 #43 ImageList_GetIconSize at :0 #44 USER32!CallWindowProcW at :0 #45 CALLDEFAULTWINDOWPROC(1705918, 514, 0, 1310774) at win32\win32callback.inc:97 #46 DOWINDOWPROC(0x3b0d610) at win32\win32callback.inc:2442 #47 WINDOWPROC(1705918, 514, 0, 1310774) at win32\win32callback.inc:2696 #48 BUTTONWNDPROC(1705918, 514, 0, 1310774) at win32\win32wsstdctrls.pp:1791 #49 USER32!AddClipboardFormatListener at :0 #50 USER32!EndTask at :0 #51 WIN32WSSTDCTRLS$_$TWIN32WSBUTTONCONTROL_$__$$_GETPREFERREDSIZE$TWINCONTROL$LONGINT$LONGINT$BOOLEAN at :0 #52 USER32!EndTask at :0 #53 ?? at :0 #54 USER32!DispatchMessageW at :0 #55 USER32!DispatchMessageW at :0 #56 APPPROCESSMESSAGES(0x3af7fd0) at win32\win32object.inc:407 #57 HANDLEMESSAGE(0x3a98408) at include\application.inc:1276 #58 RUNLOOP(0x3a98408) at include\application.inc:1413 #59 APPRUN(0x3af7fd0, {Proc = {procedure (POINTER)} 0x177ff48, Self = 0x3a98408}) at include\interfacebase.inc:54 #60 RUN(0x3a98408) at include\application.inc:1401 #61 :19 ------------------- End Stack ---------------------------

Reply by email

Martin Schreiber
to Andreas Frieß
Andreas Friec39f wrote 17 lines
Now i have inserted code in the TIntfComp to remove the link to the interface -------------------- destructor TIntfComp.Destroy; begin   FObjectHasInterface := nil;  // <<-- Crahe here now   inherited Destroy; end; -------------------- And now i it crash explicitly  at the line wher i try to 'unlink'. And the Callstack from Lazarus give me some information. The setting to nil, call fpc_intf_assign and  call IUnknown(D)._Release. But this is absolutly unwated (and unexpected) for me here.

I did not read the whole thread.
If you want to set a COM interface pointer to nil without calling _release() use
"
pointer(FObjectHasInterface):= nil;
"
It is very difficult or even impossible in Delphi and FPC to reliable mix reference counted COM interfaces with TComponent/TObject life cycle management. If you need interfaces without reference counting use CORBA interfaces.
Never use COM-interface variables if there are TObject.Destroy() calls. It is an undefined "implementation detail" when the interface variable goes out of scope, there is a risk that it goes out of scope and _release() will be called after the according object has been destroyed by a TObject.Destroy() call.

Martin

Reply by email

Andreas Frieß
to Martin Schreiber

THX for the information Martin, i have changed the line and it looks good. Very good.

This code is a prototype for me to inhibt unwanted Ref Counter changes.

Martin Schreiber wrote
pointer(FObjectHasInterface):= nil;

THX
Andreas

Reply by email