From e6f65a9e89f8383128065ba9767a6a6fd1b76a1f Mon Sep 17 00:00:00 2001 From: sobolevn Date: Fri, 7 Feb 2025 10:34:46 +0300 Subject: [PATCH] gh-129766: Fix crash on calling `warnings._release_lock` with no lock --- Lib/test/test_warnings/__init__.py | 11 +++++++++++ .../2025-02-07-10-34-09.gh-issue-129766.6n5fQZ.rst | 2 ++ Python/_warnings.c | 9 ++++++--- 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-02-07-10-34-09.gh-issue-129766.6n5fQZ.rst diff --git a/Lib/test/test_warnings/__init__.py b/Lib/test/test_warnings/__init__.py index 4bd164b8a9a82b..6f4c569d247601 100644 --- a/Lib/test/test_warnings/__init__.py +++ b/Lib/test/test_warnings/__init__.py @@ -1432,6 +1432,17 @@ class PyEnvironmentVariableTests(EnvironmentVariableTests, unittest.TestCase): module = py_warnings +class LocksTest(unittest.TestCase): + @support.cpython_only + @unittest.skipUnless(c_warnings, 'C module is required') + def test_release_lock_no_lock(self): + with self.assertRaisesRegex( + RuntimeError, + 'cannot release un-acquired lock', + ): + c_warnings._release_lock() + + class _DeprecatedTest(BaseTest, unittest.TestCase): """Test _deprecated().""" diff --git a/Misc/NEWS.d/next/Library/2025-02-07-10-34-09.gh-issue-129766.6n5fQZ.rst b/Misc/NEWS.d/next/Library/2025-02-07-10-34-09.gh-issue-129766.6n5fQZ.rst new file mode 100644 index 00000000000000..76e908300a858d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-02-07-10-34-09.gh-issue-129766.6n5fQZ.rst @@ -0,0 +1,2 @@ +Fix crash in :mod:`warnings`, when calling ``_release_lock()`` with no +existing lock. diff --git a/Python/_warnings.c b/Python/_warnings.c index bb195da9512caf..891db2743a28fc 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -240,12 +240,12 @@ warnings_lock(PyInterpreterState *interp) _PyRecursiveMutex_Lock(&st->lock); } -static inline void +static inline int warnings_unlock(PyInterpreterState *interp) { WarningsState *st = warnings_get_state(interp); assert(st != NULL); - _PyRecursiveMutex_Unlock(&st->lock); + return _PyRecursiveMutex_TryUnlock(&st->lock); } static inline bool @@ -284,7 +284,10 @@ warnings_release_lock_impl(PyObject *module) if (interp == NULL) { return NULL; } - warnings_unlock(interp); + if (warnings_unlock(interp) < 0) { + PyErr_SetString(PyExc_RuntimeError, "cannot release un-acquired lock"); + return NULL; + } Py_RETURN_NONE; }