Update of /cvsroot/perl-win32-gui/Win32-GUI
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8818

Modified Files:
        CHANGELOG GUI_Events.cpp GUI_MessageLoops.cpp 
Log Message:
Fix crashes when windows destroyed during callbacks to perl

Index: CHANGELOG
===================================================================
RCS file: /cvsroot/perl-win32-gui/Win32-GUI/CHANGELOG,v
retrieving revision 1.113
retrieving revision 1.114
diff -C2 -d -r1.113 -r1.114
*** CHANGELOG   15 Jul 2007 18:39:51 -0000      1.113
--- CHANGELOG   15 Jul 2007 18:47:13 -0000      1.114
***************
*** 16,19 ****
--- 16,21 ----
      - DC.xs - Rework DrawFrameControl() to allow DFCS_ADJUSTRECT to modify
        input parameters
+     - GUI_Events.cpp, GUI_MessageLoops.cpp - handle window being destroyed in
+       callback by checking validity with IsWindow(hwnd) in many places
  
  + [Robert May] : 20 January 2007 - Restore Original WndProc

Index: GUI_Events.cpp
===================================================================
RCS file: /cvsroot/perl-win32-gui/Win32-GUI/GUI_Events.cpp,v
retrieving revision 1.14
retrieving revision 1.15
diff -C2 -d -r1.14 -r1.15
*** GUI_Events.cpp      3 Aug 2006 22:20:02 -0000       1.14
--- GUI_Events.cpp      15 Jul 2007 18:47:13 -0000      1.15
***************
*** 10,13 ****
--- 10,26 ----
  #include "GUI.h"
  
+     /* IMPORTANT:
+      * Whenever we make a callback into perl, we cannot know what evil things
+      * the script writer will have done.  In particular, it is possible for
+      * the called code to cause the window for which the event is being
+      * handled to be destroyed before the callback returns.  If this happens
+      * we will have a non-NULL perlud pointer, but the underlying memory
+      * will have been freed.  Don't try to access perlud after a callback
+      * without checking that the window still exists.  Currently the code
+      * below gets the window handle BEFORE the callback (from perud->svSelf),
+      * and checks it afterwards with IsWindow().  This is not infallable as 
the
+      * hwnd could have been recycled - this is, however, unlikely
+      */
+ 
      /*
       
##########################################################################
***************
*** 47,50 ****
--- 60,64 ----
  
      int PerlResult = 1;
+     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
      perlud->dwPlStyle &= ~PERLWIN32GUI_EVENTHANDLING;
  
***************
*** 101,104 ****
--- 115,120 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+             
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 163,166 ****
--- 179,184 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 279,282 ****
--- 297,301 ----
      SV* acc_sub = NULL;
      int PerlResult = 1;
+     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
      perlud->dwPlStyle &= ~PERLWIN32GUI_EVENTHANDLING;
  
***************
*** 298,308 ****
              // Find for a child with AcceleratorName name
              if (strcmp (perlud->szWindowName, AcceleratorName) != 0) {
- 
-                 HWND hWndParent = handle_From(NOTXSCALL perlud->svSelf);
                  st_FindChildWindow st;
                  st.perlchild = NULL;
                  st.Name = AcceleratorName;
  
!                 EnumChildWindows(hWndParent, (WNDENUMPROC) 
FindChildWindowsProc, (LPARAM) &st);
                  perlchild = st.perlchild;
              }
--- 317,325 ----
              // Find for a child with AcceleratorName name
              if (strcmp (perlud->szWindowName, AcceleratorName) != 0) {
                  st_FindChildWindow st;
                  st.perlchild = NULL;
                  st.Name = AcceleratorName;
  
!                 EnumChildWindows(hwnd, (WNDENUMPROC) FindChildWindowsProc, 
(LPARAM) &st);
                  perlchild = st.perlchild;
              }
***************
*** 334,337 ****
--- 351,356 ----
          LEAVE;
  
+         if(!IsWindow(hwnd)) return PerlResult;
+ 
          // Must set after event call because this event can generate more 
event.
          perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 363,366 ****
--- 382,387 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 394,397 ****
--- 415,420 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 426,429 ****
--- 449,454 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 448,452 ****
      int count;
      int argtype;
!     static char *textneeded = NULL;
      if(textneeded != NULL) {
          safefree(textneeded);
--- 473,478 ----
      int count;
      int argtype;
!     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
!     static char *textneeded = NULL;           /* XXX: Not Thread Safe */
      if(textneeded != NULL) {
          safefree(textneeded);
***************
*** 515,518 ****
--- 541,546 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return textneeded;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 583,586 ****
--- 611,616 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return textneeded;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 609,612 ****
--- 639,643 ----
  
      int PerlResult = 1;
+     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
      perlud->dwPlStyle &= ~PERLWIN32GUI_EVENTHANDLING;
  
***************
*** 674,677 ****
--- 705,710 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 733,736 ****
--- 766,771 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 758,761 ****
--- 793,797 ----
      SV** events  = NULL;
      int PerlResult = 1;
+     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
      perlud->dwPlStyle &=  ~PERLWIN32GUI_EVENTHANDLING;
  
***************
*** 829,832 ****
--- 865,870 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 888,891 ****
--- 926,931 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 906,909 ****
--- 946,950 ----
      SV* newdc;
      int PerlResult = 1;
+     HWND hwnd = handle_From(NOTXSCALL perlud->svSelf);
      perlud->dwPlStyle &= ~PERLWIN32GUI_EVENTHANDLING;
  
***************
*** 949,952 ****
--- 990,995 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;
***************
*** 998,1001 ****
--- 1041,1046 ----
              LEAVE;
  
+             if(!IsWindow(hwnd)) return PerlResult;
+ 
              // Must set after event call because this event can generate more 
event.
              perlud->dwPlStyle |= PERLWIN32GUI_EVENTHANDLING;

Index: GUI_MessageLoops.cpp
===================================================================
RCS file: /cvsroot/perl-win32-gui/Win32-GUI/GUI_MessageLoops.cpp,v
retrieving revision 1.22
retrieving revision 1.23
diff -C2 -d -r1.22 -r1.23
*** GUI_MessageLoops.cpp        16 Jul 2006 11:08:27 -0000      1.22
--- GUI_MessageLoops.cpp        15 Jul 2007 18:47:13 -0000      1.23
***************
*** 262,269 ****
                  PerlResult = OnEvent[childud->iClass](NOTXSCALL childud, 
uMsg, wParam, lParam);
  
!                 if (childud->avHooks != NULL)
                      DoHook(NOTXSCALL childud, (UINT) HIWORD(wParam), wParam, 
lParam, &PerlResult, WM_COMMAND);
  
!                 if(childud->forceResult != 0) {
                      perlud->forceResult  = childud->forceResult;
                      childud->forceResult = 0;
--- 262,269 ----
                  PerlResult = OnEvent[childud->iClass](NOTXSCALL childud, 
uMsg, wParam, lParam);
  
!                 if (IsWindow((HWND)lParam) && childud->avHooks != NULL)
                      DoHook(NOTXSCALL childud, (UINT) HIWORD(wParam), wParam, 
lParam, &PerlResult, WM_COMMAND);
  
!                 if(IsWindow((HWND)lParam) && childud->forceResult != 0) {
                      perlud->forceResult  = childud->forceResult;
                      childud->forceResult = 0;
***************
*** 328,335 ****
              }
  
!             if (childud->avHooks != NULL)
                  DoHook(NOTXSCALL childud, (UINT) (((LPNMHDR) lParam)->code), 
wParam, lParam, &PerlResult, WM_NOTIFY);
  
!             if(childud->forceResult != 0) {
                  perlud->forceResult  = childud->forceResult;
                  childud->forceResult = 0;
--- 328,335 ----
              }
  
!             if (IsWindow(((LPNMHDR)lParam)->hwndFrom) && childud->avHooks != 
NULL)
                  DoHook(NOTXSCALL childud, (UINT) (((LPNMHDR) lParam)->code), 
wParam, lParam, &PerlResult, WM_NOTIFY);
  
!             if (IsWindow(((LPNMHDR)lParam)->hwndFrom) && childud->forceResult 
!= 0) {
                  perlud->forceResult  = childud->forceResult;
                  childud->forceResult = 0;
***************
*** 654,658 ****
  
      // Hook processing
!     if(perlud->avHooks != NULL) {
          DoHook(NOTXSCALL perlud, uMsg, wParam, lParam, &PerlResult,0);
      }
--- 654,658 ----
  
      // Hook processing
!     if(IsWindow(hwnd) && perlud->avHooks != NULL) {
          DoHook(NOTXSCALL perlud, uMsg, wParam, lParam, &PerlResult,0);
      }
***************
*** 660,669 ****
      // Default processing
      if(PerlResult == -1) {
!         PostMessage(hwnd, WM_EXITLOOP, (WPARAM) -1, 0);
          PerlResult = 0;
!     } else if (PerlResult != 0) {
          PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if (perlud->forceResult != 0) {
          return perlud->forceResult;
      }
--- 660,673 ----
      // Default processing
      if(PerlResult == -1) {
!         if(IsWindow(hwnd)) {
!             PostMessage(hwnd, WM_EXITLOOP, (WPARAM) -1, 0);
!         } else {
!             PostThreadMessage(GetCurrentThreadId(), WM_EXITLOOP, (WPARAM) -1, 
0);
!         }
          PerlResult = 0;
!     } else if (IsWindow(hwnd) && PerlResult != 0) {
          PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if (IsWindow(hwnd) && perlud->forceResult != 0) {
          return perlud->forceResult;
      }
***************
*** 996,1007 ****
      }
  
!     if (perlud->avHooks != NULL)
          DoHook(NOTXSCALL perlud, uMsg,wParam,lParam,&PerlResult,0);
  
! 
!     if (PerlResult != 0) {
          PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if ( perlud->forceResult != 0) {
          return perlud->forceResult;
      }
--- 1000,1010 ----
      }
  
!     if (IsWindow(hwnd) && perlud->avHooks != NULL)
          DoHook(NOTXSCALL perlud, uMsg,wParam,lParam,&PerlResult,0);
  
!     if (IsWindow(hwnd) && PerlResult != 0) {
          PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if (IsWindow(hwnd) && perlud->forceResult != 0) {
          return perlud->forceResult;
      }
***************
*** 1102,1109 ****
  
      // Hook for non interactive control
!     if (perlud->avHooks != NULL && !(perlud->dwPlStyle & 
PERLWIN32GUI_INTERACTIVE))
          DoHook(NOTXSCALL perlud, uMsg,wParam,lParam,&PerlResult,0);
  
!     if (PerlResult != 0) {
          // If interactive control, call ControlMsgLoop
          if (perlud->dwPlStyle & PERLWIN32GUI_INTERACTIVE)
--- 1105,1112 ----
  
      // Hook for non interactive control
!     if (IsWindow(hwnd) && perlud->avHooks != NULL && !(perlud->dwPlStyle & 
PERLWIN32GUI_INTERACTIVE))
          DoHook(NOTXSCALL perlud, uMsg,wParam,lParam,&PerlResult,0);
  
!     if (IsWindow(hwnd) && PerlResult != 0) {
          // If interactive control, call ControlMsgLoop
          if (perlud->dwPlStyle & PERLWIN32GUI_INTERACTIVE)
***************
*** 1112,1116 ****
              PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if (perlud->forceResult != 0) {
          return perlud->forceResult;
      }
--- 1115,1119 ----
              PerlResult = CommonMsgLoop(NOTXSCALL hwnd, uMsg, wParam, lParam, 
perlud->WndProc);
      }
!     else if (IsWindow(hwnd) && perlud->forceResult != 0) {
          return perlud->forceResult;
      }


Reply via email to