barryp / py-amqplib

Python client for the Advanced Message Queuing Procotol (AMQP)
GNU Lesser General Public License v2.1
24 stars 10 forks source link

Socket exception uses variable before it is declared #47

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
I am using v1.0.2 (most recent as of now) on Python 3.2 with the most recent 
RabbitMQ. When there is a network issue it sometimes crashes on connect 
(amqp.Connection()) with this trace:

\connection.py", line 129, in __init__
    self.transport = create_transport(host, connect_timeout, ssl)
\transport.py", line 297, in create_transport
    return TCPTransport(host, connect_timeout)
\transport.py", line 87, in __init__
    raise socket.error(msg)
UnboundLocalError: local variable 'msg' referenced before assignment

I replaced the offending line
raise socket.error(msg)
with:
raise socket.error('Unable to connect')

Original issue reported on code.google.com by fgunder...@gmail.com on 7 Feb 2012 at 9:34

GoogleCodeExporter commented 9 years ago
I'm baffled by this one, the 'msg' variable is the very first thing set in the 
__init__ method referenced in the traceback.  I don't see how it could be 
"referenced before assignment"

This is an unmodified v1.0.2 (other than the installer running 2to3)?  My copy 
after running 2to3 looks like this

------
    def __init__(self, host, connect_timeout):
        msg = 'socket.getaddrinfo() for %s returned an empty list' % host
        port = AMQP_PORT

        m = IPV6_LITERAL.match(host)
        if m:
            host = m.group(1)
            if m.group(2):
                port = int(m.group(2))
        else:
            if ':' in host:
                host, port = host.rsplit(':', 1)
                port = int(port)

        self.sock = None
        for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM, socket.SOL_TCP):
            af, socktype, proto, canonname, sa = res
            try:
                self.sock = socket.socket(af, socktype, proto)
                self.sock.settimeout(connect_timeout)
                self.sock.connect(sa)
            except socket.error as msg:
                self.sock.close()
                self.sock = None
                continue
            break

        if not self.sock:
            # Didn't connect, return the most recent error message
            raise socket.error(msg)

        self.sock.settimeout(None)
        self.sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

        self._setup_transport()

        self._write(AMQP_PROTOCOL_HEADER)
------

Original comment by barry.pe...@gmail.com on 5 Mar 2012 at 1:39

GoogleCodeExporter commented 9 years ago
My file is the same as yours. I agree, this baffled me too.

Original comment by fgunder...@gmail.com on 5 Mar 2012 at 8:32

GoogleCodeExporter commented 9 years ago
Due to a difference in exceptions between python3 and python2 the py2to3 
doesn't do a perfect job.
http://docs.python.org/py3k/howto/pyporting.html#capturing-the-currently-raised-
exception

Fix is below. Basically stores the exception explicitly instead of leaking it.

--- transport.py    2012-10-04 10:34:36.737574933 +0200
+++ transport_fixed.py  2012-10-04 10:35:17.377255648 +0200
@@ -74,7 +74,8 @@
                 self.sock = socket.socket(af, socktype, proto)
                 self.sock.settimeout(connect_timeout)
                 self.sock.connect(sa)
-            except socket.error, msg:
+            except socket.error, msg_in:
+                msg=msg_in
                 self.sock.close()
                 self.sock = None
                 continue

Original comment by killian....@megasoft.be on 4 Oct 2012 at 8:41

GoogleCodeExporter commented 9 years ago
Afterthought: isn't this also a bug in python where msg is UNSET ?

Original comment by killian....@megasoft.be on 4 Oct 2012 at 8:42