Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cache_libs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ on:
required: false
type: string
XMLSEC1_VERSION:
default: "1.3.10"
default: "1.3.11"
required: false
type: string
ZLIB_VERSION:
Expand Down
2 changes: 1 addition & 1 deletion build_support/lib_xmlsec_dependency_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class LibXmlsecDependencyBuilder:
'libxml2_version': '2.14.6', # Make sure it matches with lxml
'libxslt_version': '1.1.43',
'openssl_version': '3.6.0',
'xmlsec1_version': '1.3.10',
'xmlsec1_version': '1.3.11',
'zlib_version': '1.3.1',
}
WINDOWS_DEFAULT_LIB_VERSIONS: ClassVar[dict[str, str]] = {
Expand Down
11 changes: 11 additions & 0 deletions doc/source/modules/xmlsec.rst
Original file line number Diff line number Diff line change
@@ -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:
Expand Down
13 changes: 10 additions & 3 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -114,7 +117,11 @@ static char PyXmlSec_PyShutdown__doc__[] = \
"shutdown() -> None\n"
"Shutdowns the library and cleanup any leftover resources.\n\n"
Comment thread
mxamin marked this conversation as resolved.
"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;
Expand Down
11 changes: 6 additions & 5 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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)
13 changes: 8 additions & 5 deletions tests/test_xmlsec.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Comment thread
mxamin marked this conversation as resolved.
Loading