diff options
author | da-woods <dw-git@d-woods.co.uk> | 2021-09-27 09:58:20 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-09-27 10:58:20 +0200 |
commit | f94f26a073ee5c9987ccab6acb87ad453c6ec625 (patch) | |
tree | a7cb83fbc661e981b52285d88ae703bab40eadf3 | |
parent | 740305526a702f08e462f20a8ba6f9013126f330 (diff) | |
download | cython-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.c | 21 |
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} }; |