aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2011-08-15 10:52:09 +0200
committerArmin Rigo <arigo@tunes.org>2011-08-15 10:52:09 +0200
commit69a3c2b0e575a947cc465c3dfb8fed09a1ed8b9d (patch)
tree1bda7abd997cde23b355a5979ca19f26ece5dd56
parentFix INT/Signed. (diff)
downloadpypy-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.py4
-rw-r--r--pypy/module/_ssl/test/test_ssl.py29
-rw-r--r--pypy/rlib/ropenssl.py10
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)