[Python-checkins] bpo-33584: Fix several minor bugs in asyncio. (GH-7003)

Serhiy Storchaka webhook-mailer at python.org
Sun May 20 09:30:34 EDT 2018


https://github.com/python/cpython/commit/6655354afcd116c27486bb5ba1dfa50b369d8d85
commit: 6655354afcd116c27486bb5ba1dfa50b369d8d85
branch: master
author: Serhiy Storchaka <storchaka at gmail.com>
committer: GitHub <noreply at github.com>
date: 2018-05-20T16:30:31+03:00
summary:

bpo-33584: Fix several minor bugs in asyncio. (GH-7003)

Fix the following bugs in the C implementation:

* get_future_loop() silenced all exceptions raised when look up the get_loop
  attribute, not just an AttributeError.
* enter_task() silenced all exceptions raised when look up the current task,
  not just a KeyError.
* repr() was called for a borrowed link in enter_task() and task_step_impl().
* str() was used instead of repr() in formatting one error message (in
  Python implementation too).
* There where few reference leaks in error cases.

files:
M Lib/asyncio/tasks.py
M Modules/_asynciomodule.c

diff --git a/Lib/asyncio/tasks.py b/Lib/asyncio/tasks.py
index 3590748c477a..5df1af6642e4 100644
--- a/Lib/asyncio/tasks.py
+++ b/Lib/asyncio/tasks.py
@@ -261,7 +261,7 @@ def __step(self, exc=None):
                 # Yielding a generator is just wrong.
                 new_exc = RuntimeError(
                     f'yield was used instead of yield from for '
-                    f'generator in task {self!r} with {result}')
+                    f'generator in task {self!r} with {result!r}')
                 self._loop.call_soon(
                     self.__step, new_exc, context=self._context)
             else:
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index d66cc4cf0a5f..6d7249a58009 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -201,6 +201,7 @@ get_future_loop(PyObject *fut)
 
     _Py_IDENTIFIER(get_loop);
     _Py_IDENTIFIER(_loop);
+    PyObject *getloop;
 
     if (Future_CheckExact(fut) || Task_CheckExact(fut)) {
         PyObject *loop = ((FutureObj *)fut)->fut_loop;
@@ -208,14 +209,15 @@ get_future_loop(PyObject *fut)
         return loop;
     }
 
-    PyObject *getloop = _PyObject_GetAttrId(fut, &PyId_get_loop);
+    if (_PyObject_LookupAttrId(fut, &PyId_get_loop, &getloop) < 0) {
+        return NULL;
+    }
     if (getloop != NULL) {
         PyObject *res = _PyObject_CallNoArg(getloop);
         Py_DECREF(getloop);
         return res;
     }
 
-    PyErr_Clear();
     return _PyObject_GetAttrId(fut, &PyId__loop);
 }
 
@@ -1877,17 +1879,19 @@ enter_task(PyObject *loop, PyObject *task)
     }
     item = _PyDict_GetItem_KnownHash(current_tasks, loop, hash);
     if (item != NULL) {
+        Py_INCREF(item);
         PyErr_Format(
             PyExc_RuntimeError,
             "Cannot enter into task %R while another " \
             "task %R is being executed.",
             task, item, NULL);
+        Py_DECREF(item);
         return -1;
     }
-    if (_PyDict_SetItem_KnownHash(current_tasks, loop, task, hash) < 0) {
+    if (PyErr_Occurred()) {
         return -1;
     }
-    return 0;
+    return _PyDict_SetItem_KnownHash(current_tasks, loop, task, hash);
 }
 
 
@@ -2075,6 +2079,7 @@ _asyncio_Task_current_task_impl(PyTypeObject *type, PyObject *loop)
     if (loop == Py_None) {
         loop = get_event_loop();
         if (loop == NULL) {
+            Py_DECREF(current_task_func);
             return NULL;
         }
         ret = PyObject_CallFunctionObjArgs(current_task_func, loop, NULL);
@@ -2107,11 +2112,6 @@ _asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop)
     PyObject *res;
     PyObject *all_tasks_func;
 
-    all_tasks_func = _PyObject_GetAttrId(asyncio_mod, &PyId_all_tasks);
-    if (all_tasks_func == NULL) {
-        return NULL;
-    }
-
     if (PyErr_WarnEx(PyExc_PendingDeprecationWarning,
                      "Task.all_tasks() is deprecated, " \
                      "use asyncio.all_tasks() instead",
@@ -2119,6 +2119,11 @@ _asyncio_Task_all_tasks_impl(PyTypeObject *type, PyObject *loop)
         return NULL;
     }
 
+    all_tasks_func = _PyObject_GetAttrId(asyncio_mod, &PyId_all_tasks);
+    if (all_tasks_func == NULL) {
+        return NULL;
+    }
+
     res = PyObject_CallFunctionObjArgs(all_tasks_func, loop, NULL);
     Py_DECREF(all_tasks_func);
     return res;
@@ -2723,6 +2728,7 @@ task_step_impl(TaskObj *task, PyObject *exc)
                 PyObject *add_cb = _PyObject_GetAttrId(
                     result, &PyId_add_done_callback);
                 if (add_cb == NULL) {
+                    Py_DECREF(wrapper);
                     goto fail;
                 }
                 PyObject *stack[2];
@@ -2788,19 +2794,19 @@ task_step_impl(TaskObj *task, PyObject *exc)
     }
     if (res == 1) {
         /* `result` is a generator */
-        PyObject *ret;
-        ret = task_set_error_soon(
+        o = task_set_error_soon(
             task, PyExc_RuntimeError,
             "yield was used instead of yield from for "
-            "generator in task %R with %S", task, result);
+            "generator in task %R with %R", task, result);
         Py_DECREF(result);
-        return ret;
+        return o;
     }
 
     /* The `result` is none of the above */
-    Py_DECREF(result);
-    return task_set_error_soon(
+    o = task_set_error_soon(
         task, PyExc_RuntimeError, "Task got bad yield: %R", result);
+    Py_DECREF(result);
+    return o;
 
 self_await:
     o = task_set_error_soon(



More information about the Python-checkins mailing list