Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Catching a SIGSEGV signal on an import (http://www.velocityreviews.com/forums/t732883-catching-a-sigsegv-signal-on-an-import.html)

Ryan 09-09-2010 12:23 PM

Catching a SIGSEGV signal on an import
 
Is there anyway to catch a SIGSEGV signal that results from an import?
I'd like to get a list of all modules on the sys.path. The module
pkgutil has a nice method, walk_packages, to do just that. But, there
is a third party extension that throws a SIGSEGV when imported. I
tried to create a signal handler with the signal module like:


#!/bin/env python
import pkgutil
import signal
import traceback

def handler(signal, stackframe):
raise ImportError

# Handle seg faults that may occur during an import
signal.signal(signal.SIGSEGV, handler)

if __name__ == "__main__":
goodMods = []

def onerror(pkgName):
sys.stdout.write('Unable to import package %s\n' % pkgName)
traceback.print_exc(file=sys.stdout)
sys.stdout.write('\n')
#sys.stdout.flush()

for importer, mod, ispkg in pkgutil.walk_packages(path=None,
onerror=onerror):
goodMods.append(mod)

for m in goodMods:
sys.stdout.write(m + '\n')
sys.stdout.flush()

This sometimes works. But, since SIGSEGV is asynchronous it is not
guaranteed to work all the time. In general, is there anyway to catch
a SIGSEGV on import? If so, is there a way to use that with
pkgutil.walk_packages to get all the modules on sys.path?

Thanks,
Ryan


Nobody 09-09-2010 09:20 PM

Re: Catching a SIGSEGV signal on an import
 
On Thu, 09 Sep 2010 05:23:14 -0700, Ryan wrote:

> But, since SIGSEGV is asynchronous


SIGSEGV is almost always synchronous.

> In general, is there anyway to catch a SIGSEGV on import?


No. If SIGSEGV is raised, it often indicates that memory has been
corrupted. At that point, you can't assume that the Python runtime is
still functional.

In general, even attempting to catch it is a bad idea. Particularly in a
high-level language; getting it right in C is hard enough.


Chris Torek 10-19-2010 08:43 AM

Re: Catching a SIGSEGV signal on an import
 
(I realize this is old but I am recovering from dental surgery and,
while on the Good Drugs for the pain, going through old stuff on
purpose :-) )

>On Thu, 09 Sep 2010 05:23:14 -0700, Ryan wrote:
>> In general, is there anyway to catch a SIGSEGV on import?


In article <pan.2010.09.09.21.20.26.16000@nowhere.com>,
Nobody <nobody@nowhere.com> wrote:
>No. If SIGSEGV is raised, it often indicates that memory has been
>corrupted. At that point, you can't assume that the Python runtime is
>still functional.


Indeed.

Still, there *is* a way to do this, should you choose to live
somewhat dangerously.

First, make a copy of the original process. Using Unix as an
example:

pid = os.fork()
if pid == 0:
# child
import untrustworthy
os._exit(0)

The import will either succeed or fail. If it fails with a SIGSEGV
the child process will die; if not, the child will move on to the
next statement and exit (using os._exit() to bypass exit handlers,
since this is a forked child etc).

The parent can then do a waitpid and see whether the child was able
to do the import.

The obvious flaw in this method is that something that causes Python
to die with a SIGSEGV when imported probably has some serious bugs
in it, and depending on the state of the importing process, these
bugs might not cause a problem immediately, but instead set time-bombs
that will go off later. In this case, the child import will succeed
and the parent will then trust the import itself (note that you
have to re-do the same import in the parent as it is completely
independent after the fork()). Still, if you are dead set on the
idea, the test code below that I threw together here may be helpful.

-------

import os, signal, sys

pid = os.fork()
if pid == 0:
# deliberately not checking len(sys.argv) nor using try
# this allows you to see what happens if you run "python t.py"
# instead of "python t.py sig" or "python t.py fail" or
# "python t.py ok", for instance.
if sys.argv[1] == 'sig':
os.kill(os.getpid(), signal.SIGSEGV)
if sys.argv[1] == 'fail':
os._exit(1)
# Replace the above stuff with the untrustworthy "import",
# assuming you like the general idea.
os._exit(0)

print 'parent: child =', pid
wpid, status = os.waitpid(pid, 0)
print 'wpid =', wpid, 'status =', status
if os.WIFSIGNALED(status):
print 'child died from signal', os.WTERMSIG(status)
if os.WCOREDUMP(status):
print '(core dumped)'
elif os.WIFEXITED(status):
print 'child exited with', os.WEXITSTATUS(status)
# at this point the parent can repeat the "import"
else:
print 'I am confused, maybe I got the wrong pid'

-------

The same kind of thing can be done on other OSes, but all the details
will differ.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html


All times are GMT. The time now is 04:42 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.