View Issue Details

IDProjectCategoryView StatusLast Update
0019253LazarusLCLpublic2011-10-17 11:30
ReporterLudo BrandsAssigned ToFelipe Monteiro de Carvalho 
PrioritynormalSeveritycrashReproducibilityalways
Status closedResolutionfixed 
Product Version0.9.31 (SVN)Product Build 
Target VersionFixed in Version0.9.31 (SVN) 
Summary0019253: LCL in dylib crashes host application when library unloaded.
DescriptionCreated a dynamic library that includes the LCL. The library displays a modal form for configuration purposes. This all works fine.But when the library is unloaded and when I select another application (pushing the current app to the background), the host application (ODBC Administrator in my case) crashes with a KERN_INVALID_ADRESSS. The back trace in the crash report shows a call to an invalid address from com.apple.HIToolbox SendEventToTargetInternal(OpaqueEventRef*,..).
Running the application in gdb, I found out that the crash address corresponds to TCarbonWidgetSet.CarbonApp_Deactivated in carbonobject.inc. I conclude that the application still tries to send events to the library although the library is unloaded.
Looking at the sources, it appears that the CarbonApp_Deactivated event handler is installed in TCarbonWidgetSet.RegisterEvents, but is never removed. That works fine when the LCL is part of the application since stopping the application removes the event target all together. For LCL in a library, if I understand this correctly, the event target is the host application and the event handlers installed by LCL remain in the event chain even when the library is unloaded.
Additional InformationOSX 10.5.7
fpc 2.5.1 17360
lazarus svn 30416
TagsNo tags attached.
Fixed in Revision32931
LazTarget0.99.0
WidgetsetCarbon
Attached Files
  • events.diff (2,957 bytes)
    Index: carbonobject.inc
    ===================================================================
    --- carbonobject.inc	(revision 30416)
    +++ carbonobject.inc	(working copy)
    @@ -225,7 +225,8 @@
                 FillChar(Msg, SizeOf(Msg), 0);
                 Msg.msg := LM_ACTIVATE;
                 CarbonMenu.LCLMenuItem.Dispatch(Msg);
    -            CarbonMenu.Parent.Dismissed:=0;
    +            if assigned(CarbonMenu.Parent) then  // if parent not closed
    +              CarbonMenu.Parent.Dismissed:=0;
                 Result := noErr;
                 Exit;
               end else
    @@ -1026,23 +1027,23 @@
       //DebugLn('TCarbonWidgetSet.RegisterEvents');
       TmpSpec := MakeEventSpec(kEventClassCommand, kEventCommandProcess);
       InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_CommandProcess),
    -    1, @TmpSpec, nil, nil);
    +    1, @TmpSpec, nil, @FAEventHandlerRef[0]);
         
       TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppShown);
       InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Shown),
    -    1, @TmpSpec, nil, nil);
    +    1, @TmpSpec, nil, @FAEventHandlerRef[1]);
         
       TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppHidden);
       InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Hidden),
    -    1, @TmpSpec, nil, nil);
    +    1, @TmpSpec, nil, @FAEventHandlerRef[2]);
     
       TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppDeactivated);
       InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Deactivated),
    -    1, @TmpSpec, nil, nil);
    +    1, @TmpSpec, nil, @FAEventHandlerRef[3]);
     
       TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppActivated);
       InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Activated),
    -    1, @TmpSpec, nil, nil);
    +    1, @TmpSpec, nil, @FAEventHandlerRef[4]);
     
       FOpenEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Open));
       FQuitEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Quit));
    @@ -1064,6 +1065,9 @@
       Tells Carbon to halt the application
      ------------------------------------------------------------------------------}
     procedure TCarbonWidgetSet.AppTerminate;
    +var i:integer;
    +const
    +  SName = 'AppTerminate';
     begin
       if FTerminating then Exit;
       {$IFDEF VerboseObject}
    @@ -1071,6 +1075,9 @@
       {$ENDIF}
       FUserTerm:=True;
       QuitApplicationEventLoop;
    +  for i:=0 to 4 do
    +    OSError(MacOSALL.RemoveEventHandler(FAEventHandlerRef[i]),
    +    TClass(Self), SName, 'RemoveEventHandler');
     end;
     
     {------------------------------------------------------------------------------
    Index: carbonint.pas
    ===================================================================
    --- carbonint.pas	(revision 30416)
    +++ carbonint.pas	(working copy)
    @@ -77,7 +77,7 @@
         FAppLoop: TApplicationMainLoop;
         FAppStdEvents: Boolean;
         fMenuEnabled: Boolean;
    -
    +    FAEventHandlerRef: array[0..10] of EventHandlerRef;
         {$ifdef CarbonUseCocoa}
           pool: NSAutoreleasePool;
         {$endif}
    
    events.diff (2,957 bytes)

Activities

Ludo Brands

2011-04-28 16:29

developer   ~0047878

Last edited: 2011-04-28 16:38

patched TCarbonWidgetSet.RegisterEvents to save the EventHandlerRefPtrs and TCarbonWidgetSet.Appterminate to remove the saved EventHandlerRefPtrs. This solves the crash. I had to add application.terminate in the library to get to TCarbonWidgetSet.Appterminate.
I'm not sure if this is the best place to remove the event handlers though. I'll upload the patch and leave the judgement to the experts.

Edit: Note that the diff includes also the patch for 0015595: IDE crashes when attempting to view lfm as source (line 225 in carbonobject.inc)

2011-04-28 16:35

 

events.diff (2,957 bytes)
Index: carbonobject.inc
===================================================================
--- carbonobject.inc	(revision 30416)
+++ carbonobject.inc	(working copy)
@@ -225,7 +225,8 @@
             FillChar(Msg, SizeOf(Msg), 0);
             Msg.msg := LM_ACTIVATE;
             CarbonMenu.LCLMenuItem.Dispatch(Msg);
-            CarbonMenu.Parent.Dismissed:=0;
+            if assigned(CarbonMenu.Parent) then  // if parent not closed
+              CarbonMenu.Parent.Dismissed:=0;
             Result := noErr;
             Exit;
           end else
@@ -1026,23 +1027,23 @@
   //DebugLn('TCarbonWidgetSet.RegisterEvents');
   TmpSpec := MakeEventSpec(kEventClassCommand, kEventCommandProcess);
   InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_CommandProcess),
-    1, @TmpSpec, nil, nil);
+    1, @TmpSpec, nil, @FAEventHandlerRef[0]);
     
   TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppShown);
   InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Shown),
-    1, @TmpSpec, nil, nil);
+    1, @TmpSpec, nil, @FAEventHandlerRef[1]);
     
   TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppHidden);
   InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Hidden),
-    1, @TmpSpec, nil, nil);
+    1, @TmpSpec, nil, @FAEventHandlerRef[2]);
 
   TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppDeactivated);
   InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Deactivated),
-    1, @TmpSpec, nil, nil);
+    1, @TmpSpec, nil, @FAEventHandlerRef[3]);
 
   TmpSpec := MakeEventSpec(kEventClassApplication, kEventAppActivated);
   InstallApplicationEventHandler(RegisterEventHandler(@CarbonApp_Activated),
-    1, @TmpSpec, nil, nil);
+    1, @TmpSpec, nil, @FAEventHandlerRef[4]);
 
   FOpenEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Open));
   FQuitEventHandlerUPP := NewAEEventHandlerUPP(AEEventHandlerProcPtr(@CarbonApp_Quit));
@@ -1064,6 +1065,9 @@
   Tells Carbon to halt the application
  ------------------------------------------------------------------------------}
 procedure TCarbonWidgetSet.AppTerminate;
+var i:integer;
+const
+  SName = 'AppTerminate';
 begin
   if FTerminating then Exit;
   {$IFDEF VerboseObject}
@@ -1071,6 +1075,9 @@
   {$ENDIF}
   FUserTerm:=True;
   QuitApplicationEventLoop;
+  for i:=0 to 4 do
+    OSError(MacOSALL.RemoveEventHandler(FAEventHandlerRef[i]),
+    TClass(Self), SName, 'RemoveEventHandler');
 end;
 
 {------------------------------------------------------------------------------
Index: carbonint.pas
===================================================================
--- carbonint.pas	(revision 30416)
+++ carbonint.pas	(working copy)
@@ -77,7 +77,7 @@
     FAppLoop: TApplicationMainLoop;
     FAppStdEvents: Boolean;
     fMenuEnabled: Boolean;
-
+    FAEventHandlerRef: array[0..10] of EventHandlerRef;
     {$ifdef CarbonUseCocoa}
       pool: NSAutoreleasePool;
     {$endif}
events.diff (2,957 bytes)

Vincent Snijders

2011-10-05 15:43

manager   ~0052568

Target version 0.99 for review of the patch.

Felipe Monteiro de Carvalho

2011-10-17 08:03

developer   ~0053074

Thanks, applied.

Issue History

Date Modified Username Field Change
2011-04-28 15:16 Ludo Brands New Issue
2011-04-28 15:16 Ludo Brands Widgetset => Carbon
2011-04-28 16:29 Ludo Brands Note Added: 0047878
2011-04-28 16:35 Ludo Brands File Added: events.diff
2011-04-28 16:38 Ludo Brands Note Edited: 0047878
2011-10-05 15:42 Vincent Snijders LazTarget => 0.99.0
2011-10-05 15:42 Vincent Snijders Status new => acknowledged
2011-10-05 15:42 Vincent Snijders Target Version => 0.99.0
2011-10-05 15:43 Vincent Snijders Note Added: 0052568
2011-10-17 08:03 Felipe Monteiro de Carvalho Fixed in Revision => 32931
2011-10-17 08:03 Felipe Monteiro de Carvalho Status acknowledged => resolved
2011-10-17 08:03 Felipe Monteiro de Carvalho Fixed in Version => 0.9.31 (SVN)
2011-10-17 08:03 Felipe Monteiro de Carvalho Resolution open => fixed
2011-10-17 08:03 Felipe Monteiro de Carvalho Assigned To => Felipe Monteiro de Carvalho
2011-10-17 08:03 Felipe Monteiro de Carvalho Note Added: 0053074
2011-10-17 11:30 Ludo Brands Status resolved => closed