]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-105987: Fix reference counting issue in `_asyncio._swap_current_task` (#105989)
authorchgnrdv <52372310+chgnrdv@users.noreply.github.com>
Sat, 24 Jun 2023 05:23:24 +0000 (08:23 +0300)
committerGitHub <noreply@github.com>
Sat, 24 Jun 2023 05:23:24 +0000 (10:53 +0530)
Lib/test/test_asyncio/test_eager_task_factory.py
Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst [new file with mode: 0644]
Modules/_asynciomodule.c

index 49d5dbb8940a966e31a422c083a1b9923848fd67..fc9ad8eb43bb1b775ecf52a442e0b73e3d0ea470 100644 (file)
@@ -7,6 +7,8 @@ import unittest
 from unittest import mock
 from asyncio import tasks
 from test.test_asyncio import utils as test_utils
+import test.support
+from test.support.script_helper import assert_python_ok
 
 MOCK_ANY = mock.ANY
 
@@ -222,6 +224,23 @@ class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase
 class CEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, test_utils.TestCase):
     Task = getattr(tasks, '_CTask', None)
 
+    def test_issue105987(self):
+        code = """if 1:
+        from _asyncio import _swap_current_task
+
+        class DummyTask:
+            pass
+
+        class DummyLoop:
+            pass
+
+        l = DummyLoop()
+        _swap_current_task(l, DummyTask())
+        t = _swap_current_task(l, None)
+        """
+
+        _, out, err = assert_python_ok("-c", code)
+        self.assertFalse(err)
 
 class AsyncTaskCounter:
     def __init__(self, loop, *, task_class, eager):
diff --git a/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst b/Misc/NEWS.d/next/Library/2023-06-22-15-21-11.gh-issue-105987.T7Kzrb.rst
new file mode 100644 (file)
index 0000000..0bc97da
--- /dev/null
@@ -0,0 +1 @@
+Fix crash due to improper reference counting in :mod:`asyncio` eager task factory internal routines.
index 4b84c1de66be0e4826ef8739f8e255b3bb5f717f..5b28f2dd28a2212253c7a40506cbceae4d30ea72 100644 (file)
@@ -2047,20 +2047,23 @@ swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task)
         }
         prev_task = Py_None;
     }
+    Py_INCREF(prev_task);
 
     if (task == Py_None) {
         if (_PyDict_DelItem_KnownHash(state->current_tasks, loop, hash) == -1) {
-            return NULL;
+            goto error;
         }
     } else {
         if (_PyDict_SetItem_KnownHash(state->current_tasks, loop, task, hash) == -1) {
-            return NULL;
+            goto error;
         }
     }
 
-    Py_INCREF(prev_task);
-
     return prev_task;
+
+error:
+    Py_DECREF(prev_task);
+    return NULL;
 }
 
 /* ----- Task */