https://github.com/lsh123/xmlsec/issues/1148 https://github.com/xmlsec/python-xmlsec/pull/422 https://github.com/xmlsec/python-xmlsec/commit/5e8b4e6aa133c358b8aaf8e17ceb5b3b7fea78e8 From 5e8b4e6aa133c358b8aaf8e17ceb5b3b7fea78e8 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Tue, 28 Apr 2026 09:19:53 +0200 Subject: [PATCH] Bump xmlsec1 unix lib to 1.3.11 (#422) xmlsec1 1.3.11 may call OPENSSL_cleanup() from the OpenSSL backend during shutdown. OpenSSL cannot be reinitialized in the same process after that cleanup runs. Update the lifecycle test to call init() before shutdown(), run it last, and stop testing shutdown/init reinitialization. Document the new lifecycle constraint in the module docs and runtime docstrings. See https://github.com/lsh123/xmlsec/issues/1148 for details. --- a/doc/source/modules/xmlsec.rst +++ b/doc/source/modules/xmlsec.rst @@ -1,6 +1,17 @@ ``xmlsec`` ---------- +Lifecycle +~~~~~~~~~ + +The module initializes the underlying xmlsec library on import. Applications +that call :func:`xmlsec.shutdown` should treat it as process-final and should +not call :func:`xmlsec.init` afterwards. + +This is required because upstream xmlsec1 versions starting with 1.3.11 may +call ``OPENSSL_cleanup()`` during shutdown when using the OpenSSL backend. +OpenSSL cannot be reinitialized in the same process after that cleanup has run. + .. automodule:: xmlsec :members: :undoc-members: --- a/src/main.c +++ b/src/main.c @@ -101,8 +101,11 @@ static int PyXmlSec_Init(void) { static char PyXmlSec_PyInit__doc__[] = \ "init() -> None\n" "Initializes the library for general operation.\n\n" - "This is called upon library import and does not need to be called\n" - "again :func:`~.shutdown` is called explicitly).\n"; + "This is called upon library import and normally does not need to be\n" + "called explicitly. It is only valid before shutdown() has been called.\n\n" + "Calling init() after shutdown() is unsupported because upstream\n" + "xmlsec1 1.3.11+ may call OPENSSL_cleanup() during shutdown, and OpenSSL\n" + "cannot be reinitialized in the same process after that cleanup.\n"; static PyObject* PyXmlSec_PyInit(PyObject *self) { if (PyXmlSec_Init() < 0) { return NULL; @@ -114,7 +117,11 @@ static char PyXmlSec_PyShutdown__doc__[] = \ "shutdown() -> None\n" "Shutdowns the library and cleanup any leftover resources.\n\n" "This is called automatically upon interpreter termination and\n" - "should not need to be called explicitly."; + "should not need to be called explicitly.\n\n" + "Shutdown is process-final. Do not call init() after shutdown(),\n" + "because upstream xmlsec1 1.3.11+ may call OPENSSL_cleanup() during shutdown,\n" + "and OpenSSL cannot be reinitialized in the same process after that\n" + "cleanup."; static PyObject* PyXmlSec_PyShutdown(PyObject* self) { PyXmlSec_Free(free_mode); Py_RETURN_NONE; --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,11 @@ def pytest_collection_modifyitems(items): - """Put the module init test first. + """Put the module shutdown test last. - This way, we implicitly check whether any subsequent test fails because of module reinitialization. + xmlsec shutdown is process-final with OpenSSL cleanup introduced in + xmlsec1 1.3.11, so no tests should use xmlsec after it runs. """ - def module_init_tests_first(item): - return int('test_xmlsec.py::TestModule::test_reinitialize_module' not in item.nodeid) + def module_init_shutdown_tests_last(item): + return int('test_xmlsec.py::TestModule::test_init_shutdown_module' in item.nodeid) - items.sort(key=module_init_tests_first) + items.sort(key=module_init_shutdown_tests_last) --- a/tests/test_xmlsec.py +++ b/tests/test_xmlsec.py @@ -3,11 +3,14 @@ class TestModule(base.TestMemoryLeaks): - def test_reinitialize_module(self): - """This test doesn't explicitly verify anything, but will be invoked first in the suite. + iterations = 0 - So if the subsequent tests don't fail, we know that the ``init()``/``shutdown()`` - function pair doesn't break anything. + def test_init_shutdown_module(self): + """Check explicit initialization before final module shutdown. + + This test is invoked last because shutdown is process-final: since + xmlsec1 1.3.11, its OpenSSL backend may call OPENSSL_cleanup(), after + which OpenSSL cannot be reinitialized in the same process. """ - xmlsec.shutdown() xmlsec.init() + xmlsec.shutdown()