Catching a SIGSEGV signal on an import

Chris Torek nospam at torek.net
Tue Oct 19 04:43:21 EDT 2010


(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 at nowhere.com>,
Nobody  <nobody at 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 (40°39.22'N, 111°50.29'W)  +1 801 277 2603
email: gmail (figure it out)      http://web.torek.net/torek/index.html



More information about the Python-list mailing list