From 325b5afd1f073bbd652332cc05f54125b5c8992c Mon Sep 17 00:00:00 2001 From: Jakub Stasiak Date: Thu, 16 Oct 2014 00:01:29 +0100 Subject: [PATCH] Fix "maximum recursion depth exceeded in GreenSocket.__del__" Closes #137 Closes #148 --- eventlet/greenio.py | 10 +++++++++- tests/greenio_test.py | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/eventlet/greenio.py b/eventlet/greenio.py index a67d45b53c..f44096e91a 100644 --- a/eventlet/greenio.py +++ b/eventlet/greenio.py @@ -119,6 +119,9 @@ class GreenSocket(object): to save syscalls. """ + # This placeholder is to prevent __getattr__ from creating an infinite call loop + fd = None + def __init__(self, family_or_realsock=socket.AF_INET, *args, **kwargs): should_set_nonblocking = kwargs.pop('set_nonblocking', True) if isinstance(family_or_realsock, six.integer_types): @@ -175,6 +178,8 @@ def _set_io_refs(self, value): # If we find such attributes - only attributes having __get__ might be cached. # For now - I do not want to complicate it. def __getattr__(self, name): + if self.fd is None: + raise AttributeError(name) attr = getattr(self.fd, name) setattr(self, name, attr) return attr @@ -216,7 +221,10 @@ def _mark_as_closed(self): self._closed = True def __del__(self): - self.close() + # This is in case self.close is not assigned yet (currently the constructor does it) + close = getattr(self, 'close', None) + if close is not None: + close() def connect(self, address): if self.act_non_blocking: diff --git a/tests/greenio_test.py b/tests/greenio_test.py index ba3a8268ce..8993e85d09 100644 --- a/tests/greenio_test.py +++ b/tests/greenio_test.py @@ -9,10 +9,12 @@ import sys import tempfile +from nose.tools import eq_ + from eventlet import event, greenio, debug from eventlet.hubs import get_hub from eventlet.green import select, socket, time, ssl -from eventlet.support import get_errno, six +from eventlet.support import capture_stderr, get_errno, six from tests import ( LimitedTestCase, main, skip_with_pyevent, skipped, skip_if, skip_on_windows, @@ -895,5 +897,21 @@ def test_set_nonblocking(): assert new_flags == (orig_flags | os.O_NONBLOCK) +def test_socket_del_fails_gracefully_when_not_fully_initialized(): + # Regression introduced in da87716714689894f23d0db7b003f26d97031e83, reported in: + # * GH #137 https://github.com/eventlet/eventlet/issues/137 + # * https://bugs.launchpad.net/oslo.messaging/+bug/1369999 + + class SocketSubclass(socket.socket): + + def __init__(self): + pass + + with capture_stderr() as err: + SocketSubclass() + + assert err.getvalue() == '' + + if __name__ == '__main__': main()