diff options
author | 2011-08-15 10:52:09 +0200 | |
---|---|---|
committer | 2011-08-15 10:52:09 +0200 | |
commit | 69a3c2b0e575a947cc465c3dfb8fed09a1ed8b9d (patch) | |
tree | 1bda7abd997cde23b355a5979ca19f26ece5dd56 | |
parent | Fix INT/Signed. (diff) | |
download | pypy-69a3c2b0e575a947cc465c3dfb8fed09a1ed8b9d.tar.gz pypy-69a3c2b0e575a947cc465c3dfb8fed09a1ed8b9d.tar.bz2 pypy-69a3c2b0e575a947cc465c3dfb8fed09a1ed8b9d.zip |
Can't call these ropenssl methods without releasing
the GIL. They may call back RPython code that needs
to acquire some locks! Baaaaah**42. Instead make
sure not to call them from a __del__, with some
enqueue_for_destruction().
(transplanted from ab978bd157c94b51409d330a400b854127e86692)
-rw-r--r-- | pypy/module/_ssl/interp_ssl.py | 4 | ||||
-rw-r--r-- | pypy/module/_ssl/test/test_ssl.py | 29 | ||||
-rw-r--r-- | pypy/rlib/ropenssl.py | 10 |
3 files changed, 29 insertions, 14 deletions
diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py index 09481d17eb..bddcbeda43 100644 --- a/pypy/module/_ssl/interp_ssl.py +++ b/pypy/module/_ssl/interp_ssl.py @@ -138,6 +138,10 @@ class SSLObject(Wrappable): return self.space.wrap(rffi.charp2str(self._issuer)) def __del__(self): + self.enqueue_for_destruction(self.space, SSLObject.destructor, + '__del__() method of ') + + def destructor(self): if self.peer_cert: libssl_X509_free(self.peer_cert) if self.ssl: diff --git a/pypy/module/_ssl/test/test_ssl.py b/pypy/module/_ssl/test/test_ssl.py index a1bf7de86e..f81251b404 100644 --- a/pypy/module/_ssl/test/test_ssl.py +++ b/pypy/module/_ssl/test/test_ssl.py @@ -63,7 +63,7 @@ class AppTestSSL: _ssl.RAND_egd("entropy") def test_sslwrap(self): - import _ssl, _socket, sys + import _ssl, _socket, sys, gc if sys.platform == 'darwin': skip("hangs indefinitely on OSX (also on CPython)") s = _socket.socket() @@ -73,15 +73,19 @@ class AppTestSSL: assert exc.value.errno == 2 # Cannot find file (=not a socket) else: assert exc.value.errno == 32 # Broken pipe + del exc, ss, s + gc.collect() # force the destructor() to be called now def test_async_closed(self): - import _ssl, _socket + import _ssl, _socket, gc s = _socket.socket() s.settimeout(3) ss = _ssl.sslwrap(s, 0) s.close() exc = raises(_ssl.SSLError, ss.write, "data") assert exc.value.strerror == "Underlying socket has been closed." + del exc, ss, s + gc.collect() # force the destructor() to be called now class AppTestConnectedSSL: @@ -104,42 +108,47 @@ class AppTestConnectedSSL: """) def test_connect(self): - import socket + import socket, gc ss = socket.ssl(self.s) self.s.close() + del ss; gc.collect() def test_server(self): - import socket + import socket, gc ss = socket.ssl(self.s) assert isinstance(ss.server(), str) self.s.close() + del ss; gc.collect() def test_issuer(self): - import socket + import socket, gc ss = socket.ssl(self.s) assert isinstance(ss.issuer(), str) self.s.close() + del ss; gc.collect() def test_write(self): - import socket + import socket, gc ss = socket.ssl(self.s) raises(TypeError, ss.write, 123) num_bytes = ss.write("hello\n") assert isinstance(num_bytes, int) assert num_bytes >= 0 self.s.close() + del ss; gc.collect() def test_read(self): - import socket + import socket, gc ss = socket.ssl(self.s) raises(TypeError, ss.read, "foo") ss.write("hello\n") data = ss.read() assert isinstance(data, str) self.s.close() + del ss; gc.collect() def test_read_upto(self): - import socket + import socket, gc ss = socket.ssl(self.s) raises(TypeError, ss.read, "foo") ss.write("hello\n") @@ -148,15 +157,17 @@ class AppTestConnectedSSL: assert len(data) == 10 assert ss.pending() > 50 # many more bytes to read self.s.close() + del ss; gc.collect() def test_shutdown(self): - import socket, ssl, sys + import socket, ssl, sys, gc if sys.platform == 'darwin': skip("get also on CPython: error: [Errno 0]") ss = socket.ssl(self.s) ss.write("hello\n") assert ss.shutdown() is self.s._sock raises(ssl.SSLError, ss.write, "hello\n") + del ss; gc.collect() class AppTestConnectedSSL_Timeout(AppTestConnectedSSL): # Same tests, with a socket timeout diff --git a/pypy/rlib/ropenssl.py b/pypy/rlib/ropenssl.py index 573c3dbf48..ae545338c8 100644 --- a/pypy/rlib/ropenssl.py +++ b/pypy/rlib/ropenssl.py @@ -197,7 +197,7 @@ ssl_external('X509_NAME_get_entry', [X509_NAME, rffi.INT], X509_NAME_ENTRY) ssl_external('X509_NAME_ENTRY_get_object', [X509_NAME_ENTRY], ASN1_OBJECT) ssl_external('X509_NAME_ENTRY_get_data', [X509_NAME_ENTRY], ASN1_STRING) ssl_external('i2d_X509', [X509, rffi.CCHARPP], rffi.INT) -ssl_external('X509_free', [X509], lltype.Void, threadsafe=False) +ssl_external('X509_free', [X509], lltype.Void) ssl_external('X509_get_notBefore', [X509], ASN1_TIME, macro=True) ssl_external('X509_get_notAfter', [X509], ASN1_TIME, macro=True) ssl_external('X509_get_serialNumber', [X509], ASN1_INTEGER) @@ -232,9 +232,9 @@ ssl_external('SSL_CIPHER_get_bits', [SSL_CIPHER, rffi.INTP], rffi.INT) ssl_external('ERR_get_error', [], rffi.INT) ssl_external('ERR_error_string', [rffi.ULONG, rffi.CCHARP], rffi.CCHARP) -ssl_external('SSL_free', [SSL], lltype.Void, threadsafe=False) -ssl_external('SSL_CTX_free', [SSL_CTX], lltype.Void, threadsafe=False) -ssl_external('CRYPTO_free', [rffi.VOIDP], lltype.Void, threadsafe=False) +ssl_external('SSL_free', [SSL], lltype.Void) +ssl_external('SSL_CTX_free', [SSL_CTX], lltype.Void) +ssl_external('CRYPTO_free', [rffi.VOIDP], lltype.Void) libssl_OPENSSL_free = libssl_CRYPTO_free ssl_external('SSL_write', [SSL, rffi.CCHARP, rffi.INT], rffi.INT) @@ -246,7 +246,7 @@ ssl_external('BIO_s_mem', [], BIO_METHOD) ssl_external('BIO_s_file', [], BIO_METHOD) ssl_external('BIO_new', [BIO_METHOD], BIO) ssl_external('BIO_set_nbio', [BIO, rffi.INT], rffi.INT, macro=True) -ssl_external('BIO_free', [BIO], rffi.INT, threadsafe=False) +ssl_external('BIO_free', [BIO], rffi.INT) ssl_external('BIO_reset', [BIO], rffi.INT, macro=True) ssl_external('BIO_read_filename', [BIO, rffi.CCHARP], rffi.INT, macro=True) ssl_external('BIO_gets', [BIO, rffi.CCHARP, rffi.INT], rffi.INT) |