This is about a ugly old bug which I dislike for long, which I can only suppress by a os._exit() near Python end. Now I found some more info. Perhaps somebody sees what it is about?

When a GUI app has ever used a win32uiole OCX like shown in the attached minimal example (pythonwin\pywin\Demos\ocx\webbrowser.py, just changed to use a standalone frame window), then at the very end of the app after all windows have been destroyed and Pythons sort of main() with destruction of all Python objects is reached, there is a SIGSEGV like shown below in python26!PyInterpreterState_Clear ().
Reproduced with various Python 2 versions.


Notes:


* Obviously extra threads are created by the browser OCX if at least one .Navigate() occurred.

* if .Navigate() is commented out, and just the Window/OCX creations/destructions are done the problem is not. (But then gdb doesn't show creation of extra threads. Thus the problem seems to have to do with extra threads.)

* "app.Run()" is commented out for a mere standalone run, to reproduce the bug easily. Thus the windows are drawn down right after creation. If not, then at exit, this (simple) app somehow doesn't terminate but seems to wait eternally because of extra IE4 threads (?). When run with gdb as shown, the hang/eternal wait yet is not and the SIGSEGV occurs after .Run() too (!?)

* the problem is not, when the example is run in Pythonwin.exe at the end of Pythonwin.exe. The problem is not when such script is run with py2exe v0.5.2 stub. (maybe that does rather quickly something like os._exit() at the end). But the problem occurs with current py2exe 0.6.9 stub, and with all normal python(w).exe's - direct start or via interactive sessions. When Pythonwin is run via python(w).exe and "import pywin.framework.startup .... app.Run()", and when then the webbcrash.py is executed, then after exit of Pythonwin the crash is there too. Thus Pythonwin.exe unlike python(w).exe seems to do just a sloppy cleanup (like py2exe0.5.2) and thus avoid the problem.

* when os._exit() is done at the end of the script, the problem is not existing: the ugly "solution" ;-) sys.exit() doesn't "solve" - probably because it doesn't prevent against destruction of all Python objects, threads ...

* pywin32 build 216  (but same with 214)

* BTW: if the original pythonwin\pywin\Demos\ocx\webbrowser.py (using a MDIClient) is run standalone through python(w).exe, there is also a ugly SIGSEGV or even worse C-level crash - now at start. It should only raise a Python exception due to the non-working MDI setup I guess.




Robert




=========== SIGSEV of webbcrash.py watched with gdb :


SIGSEGV: code "mov 0x4(%ebx),%eax" at 0x1e02e449 points to memory 0x00000004. cannot read.

C:\scratch>python26 webbcrash.py
Run() ...
Run() terminated.
==> SIGSEGV crash
[uncomment "##app.Run()"]
C:\scratch>gdb python26 webbcrash.py
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "mingw32".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from C:\bin/python26.exe...(no debugging symbols found)...done. "C:\scratch/webbcrash.py" is not a core dump: File format not recognized
(gdb) run
Starting program: C:\bin/python26.exe
         (NOTE: ITS THE SAME WITH C:\Python26\python.exe)
[New Thread 6740.0x10bc]
Python 2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)] on2
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> execfile('webbcrash.py')
Web Browser - http://www.google.com/
[New Thread 6740.0x19d0]
[New Thread 6740.0xdec]
[New Thread 6740.0x1d90]
[New Thread 6740.0x1f00]
[New Thread 6740.0x19cc]
[New Thread 6740.0x26c]
[New Thread 6740.0x118c]
[New Thread 6740.0x153c]
[New Thread 6740.0x1da0]
>>> exit()

Program received signal SIGSEGV, Segmentation fault.
0x1e02e449 in python26!PyInterpreterState_Clear ()
   from C:\WINDOWS\system32\python26.dll
(gdb) bt
#0  0x1e02e449 in python26!PyInterpreterState_Clear ()
   from C:\WINDOWS\system32\python26.dll
#1  0x00000000 in ?? ()
(gdb) disass
...
0x1e02e408 <+246>: call 0x1e02e464 <python26!PyThread_get_thread_ident>
   0x1e02e40d <+251>:   mov    %eax,0x50(%esi)
   0x1e02e410 <+254>:   mov    %edi,0x40(%esi)
   0x1e02e413 <+257>:   mov    %edi,0x28(%esi)
   0x1e02e416 <+260>:   mov    %edi,0x2c(%esi)
   0x1e02e419 <+263>:   mov    %edi,0x30(%esi)
   0x1e02e41c <+266>:   mov    %edi,0x34(%esi)
   0x1e02e41f <+269>:   mov    %edi,0x38(%esi)
   0x1e02e422 <+272>:   mov    %edi,0x3c(%esi)
   0x1e02e425 <+275>:   mov    %edi,0x18(%esi)
   0x1e02e428 <+278>:   mov    %edi,0x1c(%esi)
   0x1e02e42b <+281>:   mov    %edi,0x20(%esi)
   0x1e02e42e <+284>:   mov    %edi,0x24(%esi)
   0x1e02e431 <+287>:   cmp    %edi,0xc(%esp)
0x1e02e435 <+291>: je 0x1e02e43c <python26!PyInterpreterState_Clear+298
>
0x1e02e437 <+293>: call 0x1e03111b <python26!PyThread_create_key+31>
   0x1e02e43c <+298>:   push   $0x1
   0x1e02e43e <+300>:   pushl  0x1e204f74
0x1e02e444 <+306>: call 0x1e02e248 <python26!PyThread_acquire_lock>
=> 0x1e02e449 <+311>:   mov    0x4(%ebx),%eax
   0x1e02e44c <+314>:   pushl  0x1e204f74
   0x1e02e452 <+320>:   mov    %eax,(%esi)
   0x1e02e454 <+322>:   mov    %esi,0x4(%ebx)
0x1e02e457 <+325>: call 0x1e02e2eb <python26!PyThread_release_lock>
   0x1e02e45c <+330>:   add    $0xc,%esp
   0x1e02e45f <+333>:   pop    %edi
   0x1e02e460 <+334>:   mov    %esi,%eax
   0x1e02e462 <+336>:   pop    %esi
   0x1e02e463 <+337>:   ret
End of assembler dump.
(gdb)




=========== script to reproduce the crash (attached too)
=== slightly modified pythonwin\pywin\Demos\ocx\webbrowser.py


# This demo uses the IE4 Web Browser control.

# It catches an "OnNavigate" event, and updates the frame title.
# (event stuff by Neil Hodgson)

import win32ui, win32con, win32api, regutil
from pywin.mfc import window, activex
from win32com.client import gencache
import sys, os

WebBrowserModule = gencache.EnsureModule("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
if WebBrowserModule is None:
    raise ImportError("IE4 does not appear to be installed.")

class MyWebBrowser(activex.Control, WebBrowserModule.WebBrowser):
    pass
## def OnBeforeNavigate2(self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel):
##        self.GetParent().OnNavigate(URL)
## #print "BeforeNavigate2", pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel

##class BrowserFrame(window.MDIChildWnd):
class BrowserFrame(window.FrameWnd):
    def __init__(self, url = None):
        if url is None:
            self.url = "http://www.google.com";
        else:
            self.url = url
        pass # Dont call base class doc/view version...
    def Create(self, title, rect = None):
        style = win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
##style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
        ##self._obj_ = win32ui.CreateMDIChild()
        self._obj_ = win32ui.CreateFrame()
        self._obj_.AttachObject(self)
        self._obj_.CreateWindow(None, title, style, rect, self)
        rect = self.GetClientRect()
        rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
        self.ocx = MyWebBrowser()
self.ocx.CreateControl("Web Browser", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)
        self.ocx.Navigate(self.url)
        self.HookMessage (self.OnSize, win32con.WM_SIZE)
    def OnSize (self, params):
        rect = self.GetClientRect()
        rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
        self.ocx.SetWindowPos(0, rect, 0)
    def OnNavigate(self, url):
        title = "Web Browser - %s" % (url,)
        print title
        self.SetWindowText(title)


import pywin.mfc.thread
class MyApp(pywin.mfc.thread.WinApp):
    frame = None
    def InitInstance(self): #$pycheck_no
        global f
        self.frame = f = BrowserFrame()
        self.frame.Create("Web Browser")
        if 'pywin.debugger' not in sys.modules:
            self.SetMainFrame(self.frame)

if __name__=='__main__':
    ##win32ui.Enable3dControls()
    win32ui.EnableControlContainer()
    ##app = win32ui.GetApp()
    app = MyApp()
    app.InitInstance()
    ##f = BrowserFrame()
    ##f.Create("Web Browser")
    if 'pywin.debugger' not in sys.modules:
        ##app.SetMainFrame(f)
        print "Run() ..."
        ##app.Run()
        print "Run() terminated."
        ##f.DestroyWindow()
        ##print "f.DestroyWindow() 'ed."
        ##os._exit(0)

# This demo uses the IE4 Web Browser control.

# It catches an "OnNavigate" event, and updates the frame title.
# (event stuff by Neil Hodgson)

import win32ui, win32con, win32api, regutil
from pywin.mfc import window, activex
from win32com.client import gencache
import sys, os

WebBrowserModule = gencache.EnsureModule("{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1)
if WebBrowserModule is None:
    raise ImportError("IE4 does not appear to be installed.")

class MyWebBrowser(activex.Control, WebBrowserModule.WebBrowser):
    pass
##    def OnBeforeNavigate2(self, pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel):
##        self.GetParent().OnNavigate(URL)
##        #print "BeforeNavigate2", pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel

##class BrowserFrame(window.MDIChildWnd):
class BrowserFrame(window.FrameWnd):
    def __init__(self, url = None):
        if url is None:
            self.url = "http://www.google.com";
        else:
            self.url = url
        pass # Dont call base class doc/view version...
    def Create(self, title, rect = None):
        style = win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
        ##style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_OVERLAPPEDWINDOW
        ##self._obj_ = win32ui.CreateMDIChild()
        self._obj_ = win32ui.CreateFrame()
        self._obj_.AttachObject(self)
        self._obj_.CreateWindow(None, title, style, rect, self)
        rect = self.GetClientRect()
        rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
        self.ocx = MyWebBrowser()
        self.ocx.CreateControl("Web Browser", win32con.WS_VISIBLE | win32con.WS_CHILD, rect, self, 1000)        
        self.ocx.Navigate(self.url)
        self.HookMessage (self.OnSize, win32con.WM_SIZE)
    def OnSize (self, params):
        rect = self.GetClientRect()
        rect = (0,0,rect[2]-rect[0], rect[3]-rect[1])
        self.ocx.SetWindowPos(0, rect, 0)
    def OnNavigate(self, url):
        title = "Web Browser - %s" % (url,)
        print title
        self.SetWindowText(title)


import pywin.mfc.thread
class MyApp(pywin.mfc.thread.WinApp):
    frame = None
    def InitInstance(self): #$pycheck_no
        global f
        self.frame = f = BrowserFrame()
        self.frame.Create("Web Browser")
        if 'pywin.debugger' not in sys.modules:
            self.SetMainFrame(self.frame)

if __name__=='__main__':
    ##win32ui.Enable3dControls()
    win32ui.EnableControlContainer()
    ##app = win32ui.GetApp()
    app = MyApp()
    app.InitInstance()
    ##f = BrowserFrame()
    ##f.Create("Web Browser")
    if 'pywin.debugger' not in sys.modules:
        ##app.SetMainFrame(f)
        print "Run() ..."
        ##app.Run()
        print "Run() terminated."
        ##f.DestroyWindow()
        ##print "f.DestroyWindow() 'ed."
        ##os._exit(0)
        
#######################################################################################
## 
## Fires up the PythonWin framework via normal python(w).exe (py1.5.2 tested)
## 
#######################################################################################

import sys, win32ui, win32api, win32con

# store original console stdout/in 
constdout=sys.constdout=sys.stdout
constdin=sys.constdin=sys.stdin

def do(*paths):
    import pywin.framework.startup
    from pywin.framework.intpyapp import thisApp
    thisApp.MakeExistingDDEConnection = lambda:None # we can have more 
Pythonwin's this way
    app = thisApp
    app.InitInstance()
    try: win32api.SetConsoleTitle('PyWin Console')
    except win32api.error: pass
    #for path in args:
    #    app.OpenDocumentFile(path)
    app.Run()

def do2():
    import pywin.framework.startup
    from pywin.framework.intpyapp import thisApp
    thisApp.MakeExistingDDEConnection = lambda:None        
    app = thisApp
    win32ui.LoadStdProfileSettings=lambda x:None
    app.InitInstance()
    app.frame.ShowWindow(win32con.SW_SHOW)
    try: win32api.SetConsoleTitle('PyWin Console')
    except win32api.error: pass

def do3():
    import thread
    thread.start_new_thread( do2, () )

if __name__=='__main__' :
    try:
        del sys.argv[0] # prevent this script from being loaded into the editor
    except IndexError:
        pass
    do()

_______________________________________________
python-win32 mailing list
python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to