[Python-Dev] PyThreadState_SetAsyncExc bug?

tomer filiba tomerfiliba at gmail.com
Fri Aug 11 11:27:32 CEST 2006


opened a new bug:
http://sourceforge.net/tracker/index.php?func=detail&aid=1538556&group_id=5470&atid=105470




On 8/11/06, tomer filiba <tomerfiliba at gmail.com> wrote:
> while working on a library for raising exceptions in the context
> of another thread, i've come across a bug in PyThreadState_SetAsyncExc.
> if i raise an instance, sys.exc_info() confuses the exception value for
> the exception type, and the exception value is set None. if i raise the
> type itself, the interpreter creates an instance internally, but then i can't
> pass arguments to the exception.
>
> code:
> =====================================
> import threading
> import ctypes
>
>
> def _async_raise(tid, excobj):
>     res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,
> ctypes.py_object(excobj))
>     if res == 0:
>         raise ValueError("nonexistent thread id")
>     elif res > 1:
>         # """if it returns a number greater than one, you're in trouble,
>         # and you should call it again with exc=NULL to revert the effect"""
>         ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
>         raise SystemError("PyThreadState_SetAsyncExc failed")
>
> class Thread(threading.Thread):
>     def raise_exc(self, excobj):
>         assert self.isAlive(), "thread must be started"
>         for tid, tobj in threading._active.items():
>             if tobj is self:
>                 _async_raise(tid, excobj)
>                 break
>
>         # the thread was alive when we entered the loop, but was not found
>         # in the dict, hence it must have been already terminated.
> should we raise
>         # an exception here? silently ignore?
>
>     def terminate(self):
>         self.raise_exc(SystemExit())
>
> if __name__ == "__main__":
>     import time
>     import sys
>
>     i_am_active = False
>
>     def f():
>         global i_am_active
>         i_am_active = True
>         try:
>             try:
>                 while True:
>                     time.sleep(0.01)
>             except IOError, ex:
>                 print "IOError handler"
>             except TypeError, ex:
>                 print "TypeError handler"
>                 print "ex=", repr(ex)
>                 typ, val, tb = sys.exc_info()
>                 print "typ=", repr(typ)
>                 print "val=", repr(val)
>                 print "tb=", tb
>         finally:
>             i_am_active = False
>
>     t1 = Thread(target = f)
>     t1.start()
>     time.sleep(1)
>     t1.raise_exc(TypeError("blah blah"))
>     while i_am_active:
>         time.sleep(0.01)
>     print "!! thread terminated"
>
> output:
> =====================================
> TypeError handler
> ex= None
> typ= <exceptions.TypeError instance at 0x00C15D28>  # should be the type
> val= None # should be the instance
> tb= <traceback object at 0x00C159E0>
> !! thread terminated
>
> if i change:
> t1.raise_exc(TypeError("blah blah"))
>
> to:
> t1.raise_exc(TypeError)
>
> i get:
> =====================================
> TypeError handler
> ex= <exceptions.TypeError instance at 0x00C159B8>
> typ= <class exceptions.TypeError at 0x00B945A0>
> val= <exceptions.TypeError instance at 0x00C159B8>
> tb= <traceback object at 0x00C15D00>
> !! thread terminated
>
> but then of course i can't pass arguments to the exception
>
>
>
> -tomer
>


More information about the Python-Dev mailing list