[pypy-commit] pypy default: Can't call these ropenssl methods without releasing

arigo noreply at buildbot.pypy.org
Mon Aug 15 10:50:37 CEST 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r46513:ab978bd157c9
Date: 2011-08-15 10:52 +0200
http://bitbucket.org/pypy/pypy/changeset/ab978bd157c9/

Log:	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().

diff --git a/pypy/module/_ssl/interp_ssl.py b/pypy/module/_ssl/interp_ssl.py
--- a/pypy/module/_ssl/interp_ssl.py
+++ b/pypy/module/_ssl/interp_ssl.py
@@ -138,6 +138,10 @@
         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
--- a/pypy/module/_ssl/test/test_ssl.py
+++ b/pypy/module/_ssl/test/test_ssl.py
@@ -63,7 +63,7 @@
         _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 @@
             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 @@
             """)
 
     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 @@
         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
--- a/pypy/rlib/ropenssl.py
+++ b/pypy/rlib/ropenssl.py
@@ -197,7 +197,7 @@
 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('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_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)


More information about the pypy-commit mailing list