From a59704cf93e8594dfe59cf12d416e82a816953a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Urba=C5=84ski?= Date: Tue, 17 Feb 2015 10:48:18 +0100 Subject: [PATCH] Make sure libcrypto threadsafety callbacks are properly set up Multithreaded programs using libcrypto (part of OpenSSL) need to set up callbacks to ensure safe execution. Both Python and libpq set up those callbacks, which might lead to a conflict. To avoid leaving dangling function pointers when being unloaded, libpq sets up and removes the callbacks every time a SSL connection it opened and closed. If another Python thread is performing unrelated SSL operations (like connecting to a HTTPS server), this might lead to deadlocks, as described in http://www.postgresql.org/message-id/871tlzrlkq.fsf@wulczer.org Even if the problem will be remediated in libpq, it's still useful to have it fixed in psycopg2. The solution is to use Python's own libcrypto callbacks and completely disable handling them in libpq. --- psycopg/psycopgmodule.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/psycopg/psycopgmodule.c b/psycopg/psycopgmodule.c index 2c345a3b..61e2de57 100644 --- a/psycopg/psycopgmodule.c +++ b/psycopg/psycopgmodule.c @@ -176,6 +176,26 @@ psyco_register_type(PyObject *self, PyObject *args) } + +/* Make sure libcrypto thread callbacks are set up. */ +static void +psyco_libcrypto_threads_init(void) +{ + /* importing the ssl module sets up Python's libcrypto callbacks */ + if (PyImport_ImportModule("ssl") != NULL) { + /* disable libcrypto setup in libpq, so it won't stomp on the callbacks + that have already been set up */ +#if PG_VERSION_HEX >= 0x080400 + PQinitOpenSSL(1, 0); +#endif + } + else { + /* might mean that Python has been compiled without OpenSSL support, + fall back to relying on libpq's libcrypto locking */ + PyErr_Clear(); + } +} + /* Initialize the default adapters map * * Return 0 on success, else -1 and set an exception. @@ -814,6 +834,9 @@ INIT_MODULE(_psycopg)(void) Py_TYPE(&lobjectType) = &PyType_Type; if (PyType_Ready(&lobjectType) == -1) goto exit; + /* initialize libcrypto threading callbacks */ + psyco_libcrypto_threads_init(); + /* import mx.DateTime module, if necessary */ #ifdef HAVE_MXDATETIME Py_TYPE(&mxdatetimeType) = &PyType_Type;