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.
This commit is contained in:
Jan Urbański 2015-02-17 10:48:18 +01:00 committed by Daniele Varrazzo
parent 1b7e3c6da4
commit a59704cf93

View File

@ -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;