diff options
author | Pierre Glaser <pierreglaser@msn.com> | 2020-02-02 18:55:21 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-02-02 18:55:21 (GMT) |
commit | 0f2f35e15f9fbee44ce042b724348419d8136bc5 (patch) | |
tree | 5e97ddf0e6fa7b08990923bd77c22623a4779a80 /Modules | |
parent | 339fd46cb764277cbbdc3e78dcc5b45b156bb6ae (diff) | |
download | cpython-0f2f35e15f9fbee44ce042b724348419d8136bc5.zip cpython-0f2f35e15f9fbee44ce042b724348419d8136bc5.tar.gz cpython-0f2f35e15f9fbee44ce042b724348419d8136bc5.tar.bz2 |
bpo-39492: Fix a reference cycle between reducer_override and a Pickler instance (GH-18266)
This also needs a backport to 3.8
https://bugs.python.org/issue39492
Automerge-Triggered-By: @pitrou
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_pickle.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 25d5c8d..fc48d60 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -4455,12 +4455,13 @@ static int dump(PicklerObject *self, PyObject *obj) { const char stop_op = STOP; + int status = -1; PyObject *tmp; _Py_IDENTIFIER(reducer_override); if (_PyObject_LookupAttrId((PyObject *)self, &PyId_reducer_override, &tmp) < 0) { - return -1; + goto error; } /* Cache the reducer_override method, if it exists. */ if (tmp != NULL) { @@ -4477,7 +4478,7 @@ dump(PicklerObject *self, PyObject *obj) assert(self->proto >= 0 && self->proto < 256); header[1] = (unsigned char)self->proto; if (_Pickler_Write(self, header, 2) < 0) - return -1; + goto error; if (self->proto >= 4) self->framing = 1; } @@ -4485,9 +4486,22 @@ dump(PicklerObject *self, PyObject *obj) if (save(self, obj, 0) < 0 || _Pickler_Write(self, &stop_op, 1) < 0 || _Pickler_CommitFrame(self) < 0) - return -1; + goto error; + + // Success + status = 0; + + error: self->framing = 0; - return 0; + + /* Break the reference cycle we generated at the beginning this function + * call when setting the reducer_override attribute of the Pickler instance + * to a bound method of the same instance. This is important as the Pickler + * instance holds a reference to each object it has pickled (through its + * memo): thus, these objects wont be garbage-collected as long as the + * Pickler itself is not collected. */ + Py_CLEAR(self->reducer_override); + return status; } /*[clinic input] |