summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorda-woods <dw-git@d-woods.co.uk>2021-09-27 09:58:20 +0100
committerGitHub <noreply@github.com>2021-09-27 10:58:20 +0200
commitf94f26a073ee5c9987ccab6acb87ad453c6ec625 (patch)
treea7cb83fbc661e981b52285d88ae703bab40eadf3
parent740305526a702f08e462f20a8ba6f9013126f330 (diff)
downloadcython-f94f26a073ee5c9987ccab6acb87ad453c6ec625.tar.gz
Make __Pyx_CoroutineAwaitType non-pickleable (GH-4381)
This is explicitly tested for: https://github.com/cython/cython/blob/aea4e6b84b38223c540266f8c57093ee2039f284/tests/run/test_coroutines_pep492.pyx#L2400 It turns out some earlier versions of Python assume that C-API classes without a dict or slot are pickleable by the class name. Currently it isn't pickleable because the class name lookup is failing but this change makes it more robust. See https://github.com/cython/cython/pull/4376
-rw-r--r--Cython/Utility/Coroutine.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/Cython/Utility/Coroutine.c b/Cython/Utility/Coroutine.c
index 1332c9824..e530a078d 100644
--- a/Cython/Utility/Coroutine.c
+++ b/Cython/Utility/Coroutine.c
@@ -1501,6 +1501,22 @@ static PyObject *__Pyx_CoroutineAwait_no_new(PyTypeObject *type, PyObject *args,
}
#endif
+// In earlier versions of Python an object with no __dict__ and not __slots__ is assumed
+// to be pickleable by default. Coroutine-wrappers have significant state so shouldn't be.
+// Therefore provide a default implementation.
+// Something similar applies to heaptypes (i.e. with type_specs) with protocols 0 and 1
+// even in more recent versions.
+// We are applying this to all Python versions (hence the commented out version guard)
+// to make the behaviour explicit.
+// #if PY_VERSION_HEX < 0x03060000 || CYTHON_USE_TYPE_SPECS
+static PyObject *__Pyx_CoroutineAwait_reduce_ex(__pyx_CoroutineAwaitObject *self, PyObject *arg) {
+ CYTHON_UNUSED_VAR(arg);
+ PyErr_Format(PyExc_TypeError, "cannot pickle '%.200s' object",
+ Py_TYPE(self)->tp_name);
+ return NULL;
+}
+// #endif
+
static PyMethodDef __pyx_CoroutineAwait_methods[] = {
{"send", (PyCFunction) __Pyx_CoroutineAwait_Send, METH_O,
(char*) PyDoc_STR("send(arg) -> send 'arg' into coroutine,\nreturn next yielded value or raise StopIteration.")},
@@ -1508,6 +1524,11 @@ static PyMethodDef __pyx_CoroutineAwait_methods[] = {
(char*) PyDoc_STR("throw(typ[,val[,tb]]) -> raise exception in coroutine,\nreturn next yielded value or raise StopIteration.")},
{"close", (PyCFunction) __Pyx_CoroutineAwait_Close, METH_NOARGS,
(char*) PyDoc_STR("close() -> raise GeneratorExit inside coroutine.")},
+// only needed with type-specs or version<3.6, but included in all versions for clarity
+// #if PY_VERSION_HEX < 0x03060000 || CYTHON_USE_TYPE_SPECS
+ {"__reduce_ex__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_O, 0},
+ {"__reduce__", (PyCFunction) __Pyx_CoroutineAwait_reduce_ex, METH_NOARGS, 0},
+// #endif
{0, 0, 0, 0}
};