issue #535: core: unicode.encode() may take importer lock on 2.x

Found on Python 2.4, where import happens immediately following connect.

- Main thread executes import statement, triggers request to parent
- Broker thread attempts to deliver request via Router
- Router discovers parent has disconnected, prepares a dead message
- .dead() calls unicode.encode() to format reason string
- .encode() attemptsto import a codec module
- deadlock

----

(gdb) pystack
/usr/local/python2.4.6/lib/python2.4/encodings/__init__.py (69): search_function
<stdin> (733): dead
<stdin> (2717): _maybe_send_dead
<stdin> (2724): _invoke
<stdin> (2749): _async_route
<stdin> (1635): _receive_one
<stdin> (1603): _internal_receive
<stdin> (1613): on_receive
<stdin> (2931): _call
<stdin> (2942): _loop_once
<stdin> (2988): _do_broker_main
<stdin> (545): _profile_hook
<stdin> (3007): _broker_main
/usr/local/python2.4.6/lib/python2.4/threading.py (420): run
/usr/local/python2.4.6/lib/python2.4/threading.py (424): __bootstrap
pull/564/head
David Wilson 6 years ago
parent 72862f0bb9
commit eb9ec26622

@ -103,6 +103,9 @@ IOLOG = logging.getLogger('mitogen.io')
IOLOG.setLevel(logging.INFO)
LATIN1_CODEC = encodings.latin_1.Codec()
# str.encode() may take import lock. Deadlock possible if broker calls
# .encode() on behalf of thread currently waiting for module.
UTF8_CODEC = encodings.latin_1.Codec()
_v = False
_vv = False
@ -271,8 +274,7 @@ class Kwargs(dict):
def __init__(self, dct):
for k, v in dct.iteritems():
if type(k) is unicode:
self[k.encode()] = v
else:
k, _ = UTF8_CODEC.encode(k)
self[k] = v
def __repr__(self):
@ -735,7 +737,7 @@ class Message(object):
"""
Syntax helper to construct a dead message.
"""
kwargs['data'] = (reason or u'').encode()
kwargs['data'], _ = UTF8_CODEC.encode(reason or u'')
return cls(reply_to=IS_DEAD, **kwargs)
@classmethod
@ -1332,7 +1334,7 @@ class Importer(object):
if mod.__package__ and not PY3:
# 2.x requires __package__ to be exactly a string.
mod.__package__ = mod.__package__.encode()
mod.__package__, _ = UTF8_CODEC.encode(mod.__package__)
source = self.get_source(fullname)
try:

Loading…
Cancel
Save