Catching a SIGSEGV signal on an import

R

Ryan

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
 
N

Nobody

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.
 
C

Chris Torek

(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 :) )

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,072
Latest member
trafficcone

Latest Threads

Top