From e12d6415c01d24f852ea1b58508c0e6893a82429 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 30 Jan 2018 04:14:12 +0000 Subject: [PATCH 01/19] DECREF cls in _PyCrossInterpreterData_Lookup(). --- Python/pystate.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/pystate.c b/Python/pystate.c index a474549a8c730d..8dbda73de7015d 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1242,6 +1242,7 @@ _PyCrossInterpreterData_Lookup(PyObject *obj) break; } } + Py_DECREF(cls); PyThread_release_lock(_PyRuntime.xidregistry.mutex); return getdata; } From ce72eef3f8bfc2e62da50a3baa7f3055daa93253 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 30 Jan 2018 04:30:13 +0000 Subject: [PATCH 02/19] DECREF the id in interp_list_all(). --- Modules/_xxsubinterpretersmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index d2b5f26fae1d09..9d74b8a8b90278 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1612,7 +1612,9 @@ interp_list_all(PyObject *self) return NULL; } // insert at front of list - if (PyList_Insert(ids, 0, id) < 0) { + int res = PyList_Insert(ids, 0, id); + Py_DECREF(id); + if (res < 0) { Py_DECREF(ids); return NULL; } From 27bbab7f66354dd341c2a6b525d56058d6366b5f Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 01:33:57 +0000 Subject: [PATCH 03/19] Avoid raising RunFailedError. --- Lib/test/test__xxsubinterpreters.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 2b170443a3b638..8d8581cc139395 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -362,13 +362,15 @@ def test_bad_id(self): def test_from_current(self): main, = interpreters.list_all() id = interpreters.create() - script = dedent(""" + script = dedent(f""" import _xxsubinterpreters as _interpreters - _interpreters.destroy({}) - """).format(id) + try: + _interpreters.destroy({id}) + except RuntimeError: + pass + """) - with self.assertRaises(RuntimeError): - interpreters.run_string(id, script) + interpreters.run_string(id, script) self.assertEqual(set(interpreters.list_all()), {main, id}) def test_from_sibling(self): From c744873cee13a39f929b2dc24dde80195c96a868 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 01:35:32 +0000 Subject: [PATCH 04/19] DECREF id in _coerce_id(). --- Modules/_xxsubinterpretersmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 9d74b8a8b90278..33b036e29dd54d 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -32,6 +32,7 @@ _coerce_id(PyObject *id) return -1; } long long cid = PyLong_AsLongLong(id); + Py_DECREF(id); if (cid == -1 && PyErr_Occurred() != NULL) { PyErr_SetString(PyExc_ValueError, "'id' must be a non-negative int"); From e982d873129877788b755765b81542b0155e0ab8 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 01:38:59 +0000 Subject: [PATCH 05/19] DECREF the original error message. --- Modules/_xxsubinterpretersmodule.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 33b036e29dd54d..cd79edefca49f2 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -140,6 +140,12 @@ typedef struct _sharedexception { char *msg; } _sharedexception; +static void +_sharedexception_free(_sharedexception *exc) { + PyMem_Free(exc->msg); + PyMem_Free(exc); +} + static _sharedexception * _get_shared_exception(void) { @@ -162,7 +168,18 @@ _get_shared_exception(void) err->msg = "unable to format exception"; return err; } - err->msg = (char *)PyUnicode_AsUTF8(msg); + const char *errmsg = PyUnicode_AsUTF8(msg); + if (errmsg == NULL) { + err->msg = "unable to encode exception"; + } + err->msg = PyMem_Malloc(strlen(errmsg)+1); + if (err->msg == NULL) { + Py_DECREF(msg); + err->msg = "MemoryError: out of memory copying error message"; + return err; + } + strcpy(err->msg, errmsg); + Py_DECREF(msg); if (err->msg == NULL) { err->msg = "unable to encode exception"; } @@ -1079,6 +1096,7 @@ channelid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds) "'send' and 'recv' cannot both be False"); return NULL; } + int end = 0; if (send == 1) { if (recv == 0 || recv == -1) { @@ -1471,7 +1489,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, // Propagate any exception out to the caller. if (exc != NULL) { _apply_shared_exception(exc); - PyMem_Free(exc); + _sharedexception_free(exc); } else if (result != 0) { // We were unable to allocate a shared exception. From aac9485031de7b9c2ee78d13d4a3d9d1fa8e6ec6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 02:00:38 +0000 Subject: [PATCH 06/19] Do not explicitly check against INT64_MAX. --- Lib/test/test__xxsubinterpreters.py | 6 +++--- Modules/_xxsubinterpretersmodule.c | 15 ++++++--------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py index 8d8581cc139395..8d72ca20021486 100644 --- a/Lib/test/test__xxsubinterpreters.py +++ b/Lib/test/test__xxsubinterpreters.py @@ -763,12 +763,12 @@ def __int__(self): self.assertEqual(int(cid), 10) def test_bad_id(self): - ids = [-1, 2**64, "spam"] - for cid in ids: + for cid in [-1, 'spam']: with self.subTest(cid): with self.assertRaises(ValueError): interpreters._channel_id(cid) - + with self.assertRaises(OverflowError): + interpreters._channel_id(2**64) with self.assertRaises(TypeError): interpreters._channel_id(object()) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index cd79edefca49f2..ca850c4ccc4635 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -31,11 +31,13 @@ _coerce_id(PyObject *id) } return -1; } - long long cid = PyLong_AsLongLong(id); + int64_t cid = PyLong_AsLongLong(id); Py_DECREF(id); if (cid == -1 && PyErr_Occurred() != NULL) { - PyErr_SetString(PyExc_ValueError, - "'id' must be a non-negative int"); + if (!PyErr_ExceptionMatches(PyExc_OverflowError)) { + PyErr_SetString(PyExc_ValueError, + "'id' must be a non-negative int"); + } return -1; } if (cid < 0) { @@ -43,11 +45,6 @@ _coerce_id(PyObject *id) "'id' must be a non-negative int"); return -1; } - if (cid > INT64_MAX) { - PyErr_SetString(PyExc_ValueError, - "'id' too large (must be 64-bit int)"); - return -1; - } return cid; } @@ -1231,7 +1228,7 @@ channelid_richcompare(PyObject *self, PyObject *other, int op) if (othercid == -1 && PyErr_Occurred() != NULL) { return NULL; } - if (othercid < 0 || othercid > INT64_MAX) { + if (othercid < 0) { equal = 0; } else { From 35f60460d0106cab5da691276168a544bb3bb30d Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 05:06:30 +0000 Subject: [PATCH 07/19] Free cids when done. --- Modules/_xxsubinterpretersmodule.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index ca850c4ccc4635..f90a87de9a1902 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1840,11 +1840,11 @@ channel_list_all(PyObject *self) } PyObject *ids = PyList_New((Py_ssize_t)count); if (ids == NULL) { - // XXX free cids - return NULL; + goto finally; } - for (int64_t i=0; i < count; cids++, i++) { - PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cids, 0, + int64_t *cur = cids; + for (int64_t i=0; i < count; cur++, i++) { + PyObject *id = (PyObject *)newchannelid(&ChannelIDtype, *cur, 0, &_globals.channels, 0); if (id == NULL) { Py_DECREF(ids); @@ -1853,7 +1853,9 @@ channel_list_all(PyObject *self) } PyList_SET_ITEM(ids, i, id); } - // XXX free cids + +finally: + PyMem_Free(cids); return ids; } From 38d924ece6db72c89b96bbb30e79a4a8bda316b6 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Wed, 31 Jan 2018 05:16:09 +0000 Subject: [PATCH 08/19] DECREF other in channelid_richcompare(). --- Modules/_xxsubinterpretersmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index f90a87de9a1902..70193f8d1af5a4 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1224,7 +1224,7 @@ channelid_richcompare(PyObject *self, PyObject *other, int op) Py_RETURN_NOTIMPLEMENTED; } int64_t othercid = PyLong_AsLongLong(other); - // XXX decref other here? + Py_DECREF(other); if (othercid == -1 && PyErr_Occurred() != NULL) { return NULL; } From 4321ecf1edd15d441a2cc682412fb5b91fd2e2c3 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 2 Feb 2018 19:47:16 +0000 Subject: [PATCH 09/19] Add items to non-empty channels. --- Modules/_xxsubinterpretersmodule.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 70193f8d1af5a4..c69bd24b409a2d 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -538,6 +538,9 @@ _channel_add(_PyChannelState *chan, int64_t interp, if (chan->first == NULL) { chan->first = item; } + else { + chan->last->next = item; + } chan->last = item; res = 0; @@ -551,6 +554,7 @@ _channel_next(_PyChannelState *chan, int64_t interp) { _PyCrossInterpreterData *data = NULL; PyThread_acquire_lock(chan->mutex, WAIT_LOCK); + if (_channel_associate_end(chan, interp, 0) == NULL) { goto done; } From e5a3515af46b3c1fe94624374b68e5418a838465 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 2 Feb 2018 21:43:33 +0000 Subject: [PATCH 10/19] Add struct _sharedns and isolate related memory ops. --- Modules/_xxsubinterpretersmodule.c | 189 ++++++++++++++++++----------- 1 file changed, 119 insertions(+), 70 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index c69bd24b409a2d..64e2c2b16d81f0 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -7,6 +7,22 @@ #include "internal/pystate.h" +static char * +_copy_raw_string(PyObject *strobj) +{ + const char *str = PyUnicode_AsUTF8(strobj); + if (str == NULL) { + return NULL; + } + char *copied = PyMem_Malloc(strlen(str)+1); + if (str == NULL) { + PyErr_NoMemory(); + return NULL; + } + strcpy(copied, str); + return copied; +} + static PyInterpreterState * _get_current(void) { @@ -50,82 +66,125 @@ _coerce_id(PyObject *id) /* data-sharing-specific code ***********************************************/ -typedef struct _shareditem { - Py_UNICODE *name; - Py_ssize_t namelen; +struct _sharednsitem { + char *name; _PyCrossInterpreterData data; -} _shareditem; +}; + +static int +_sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value) +{ + item->name = _copy_raw_string(key); + if (item->name == NULL) { + return -1; + } + if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) { + return -1; + } + return 0; +} + +static void +_sharednsitem_clear(struct _sharednsitem *item) +{ + if (item->name != NULL) { + PyMem_Free(item->name); + } + _PyCrossInterpreterData_Release(&item->data); +} -void -_sharedns_clear(_shareditem *shared) +static int +_sharednsitem_apply(struct _sharednsitem *item, PyObject *ns) { - for (_shareditem *item=shared; item->name != NULL; item += 1) { - _PyCrossInterpreterData_Release(&item->data); + PyObject *name = PyUnicode_FromString(item->name); + if (name == NULL) { + return -1; } + PyObject *value = _PyCrossInterpreterData_NewObject(&item->data); + if (value == NULL) { + Py_DECREF(name); + return -1; + } + int res = PyDict_SetItem(ns, name, value); + Py_DECREF(name); + Py_DECREF(value); + return res; } -static _shareditem * -_get_shared_ns(PyObject *shareable, Py_ssize_t *lenp) +typedef struct _sharedns { + Py_ssize_t len; + struct _sharednsitem* items; +} _sharedns; + +static _sharedns * +_sharedns_new(Py_ssize_t len) +{ + _sharedns *shared = PyMem_NEW(_sharedns, 1); + if (shared == NULL) { + PyErr_NoMemory(); + return NULL; + } + shared->len = len; + shared->items = PyMem_NEW(struct _sharednsitem, len); + if (shared->items == NULL) { + PyErr_NoMemory(); + PyMem_Free(shared); + return NULL; + } + return shared; +} + +static void +_sharedns_free(_sharedns *shared) +{ + for (Py_ssize_t i=0; i < shared->len; i++) { + _sharednsitem_clear(&shared->items[i]); + } + PyMem_Free(shared->items); + PyMem_Free(shared); +} + +static _sharedns * +_get_shared_ns(PyObject *shareable) { if (shareable == NULL || shareable == Py_None) { - *lenp = 0; return NULL; } Py_ssize_t len = PyDict_Size(shareable); - *lenp = len; if (len == 0) { return NULL; } - _shareditem *shared = PyMem_NEW(_shareditem, len+1); + _sharedns *shared = _sharedns_new(len); if (shared == NULL) { return NULL; } - for (Py_ssize_t i=0; i < len; i++) { - *(shared + i) = (_shareditem){0}; - } Py_ssize_t pos = 0; for (Py_ssize_t i=0; i < len; i++) { PyObject *key, *value; if (PyDict_Next(shareable, &pos, &key, &value) == 0) { break; } - _shareditem *item = shared + i; - - if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) { - break; - } - item->name = PyUnicode_AsUnicodeAndSize(key, &item->namelen); - if (item->name == NULL) { - _PyCrossInterpreterData_Release(&item->data); + if (_sharednsitem_init(&shared->items[i], key, value) != 0) { break; } - (item + 1)->name = NULL; // Mark the next one as the last. } if (PyErr_Occurred()) { - _sharedns_clear(shared); - PyMem_Free(shared); + _sharedns_free(shared); return NULL; } return shared; } static int -_shareditem_apply(_shareditem *item, PyObject *ns) +_sharedns_apply(_sharedns *shared, PyObject *ns) { - PyObject *name = PyUnicode_FromUnicode(item->name, item->namelen); - if (name == NULL) { - return 1; - } - PyObject *value = _PyCrossInterpreterData_NewObject(&item->data); - if (value == NULL) { - Py_DECREF(name); - return 1; + for (Py_ssize_t i=0; i < shared->len; i++) { + if (_sharednsitem_apply(&shared->items[i], ns) != 0) { + return -1; + } } - int res = PyDict_SetItem(ns, name, value); - Py_DECREF(name); - Py_DECREF(value); - return res; + return 0; } // Ultimately we'd like to preserve enough information about the @@ -138,8 +197,11 @@ typedef struct _sharedexception { } _sharedexception; static void -_sharedexception_free(_sharedexception *exc) { - PyMem_Free(exc->msg); +_sharedexception_free(_sharedexception *exc) +{ + if (exc->msg != NULL) { + PyMem_Free(exc->msg); + } PyMem_Free(exc); } @@ -165,20 +227,14 @@ _get_shared_exception(void) err->msg = "unable to format exception"; return err; } - const char *errmsg = PyUnicode_AsUTF8(msg); - if (errmsg == NULL) { - err->msg = "unable to encode exception"; - } - err->msg = PyMem_Malloc(strlen(errmsg)+1); - if (err->msg == NULL) { - Py_DECREF(msg); - err->msg = "MemoryError: out of memory copying error message"; - return err; - } - strcpy(err->msg, errmsg); + + err->msg = _copy_raw_string(msg); Py_DECREF(msg); if (err->msg == NULL) { - err->msg = "unable to encode exception"; + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + err->msg = "MemoryError: out of memory copying error message"; + } + err->msg = "unable to encode and copy exception message"; } return err; } @@ -289,7 +345,8 @@ _channelend_new(int64_t interp) } static void -_channelend_free_all(_channelend *end) { +_channelend_free_all(_channelend *end) +{ while (end != NULL) { _channelend *last = end; end = end->next; @@ -1416,10 +1473,8 @@ _ensure_not_running(PyInterpreterState *interp) static int _run_script(PyInterpreterState *interp, const char *codestr, - _shareditem *shared, Py_ssize_t num_shared, - _sharedexception **exc) + _sharedns *shared, _sharedexception **exc) { - assert(num_shared >= 0); PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__"); if (main_mod == NULL) { goto error; @@ -1433,12 +1488,9 @@ _run_script(PyInterpreterState *interp, const char *codestr, // Apply the cross-interpreter data. if (shared != NULL) { - for (Py_ssize_t i=0; i < num_shared; i++) { - _shareditem *item = &shared[i]; - if (_shareditem_apply(item, ns) != 0) { - Py_DECREF(ns); - goto error; - } + if (_sharedns_apply(shared, ns) != 0) { + Py_DECREF(ns); + goto error; } } @@ -1453,7 +1505,6 @@ _run_script(PyInterpreterState *interp, const char *codestr, } return 0; - error: *exc = _get_shared_exception(); PyErr_Clear(); @@ -1468,8 +1519,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, return -1; } - Py_ssize_t num_shared = -1; - _shareditem *shared = _get_shared_ns(shareables, &num_shared); + _sharedns *shared = _get_shared_ns(shareables); if (shared == NULL && PyErr_Occurred()) { return -1; } @@ -1480,7 +1530,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, // Run the script. _sharedexception *exc = NULL; - int result = _run_script(interp, codestr, shared, num_shared, &exc); + int result = _run_script(interp, codestr, shared, &exc); // Switch back. if (save_tstate != NULL) { @@ -1498,8 +1548,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, } if (shared != NULL) { - _sharedns_clear(shared); - PyMem_Free(shared); + _sharedns_free(shared); } return result; From 0c0fa3df7cc1f003fefabd4f620857f4b93c986b Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Fri, 2 Feb 2018 23:00:20 +0000 Subject: [PATCH 11/19] Clean up memory ops for _sharedexception. --- Modules/_xxsubinterpretersmodule.c | 129 +++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 26 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 64e2c2b16d81f0..3e1abf635576bd 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -193,48 +193,91 @@ _sharedns_apply(_sharedns *shared, PyObject *ns) // of the exception in the calling interpreter. typedef struct _sharedexception { + char *name; char *msg; } _sharedexception; +static _sharedexception * +_sharedexception_new(void) +{ + _sharedexception *err = PyMem_NEW(_sharedexception, 1); + if (err == NULL) { + PyErr_NoMemory(); + return NULL; + } + err->name = NULL; + err->msg = NULL; + return err; +} + static void -_sharedexception_free(_sharedexception *exc) +_sharedexception_clear(_sharedexception *exc) { + if (exc->name != NULL) { + PyMem_Free(exc->name); + } if (exc->msg != NULL) { PyMem_Free(exc->msg); } +} + +static void +_sharedexception_free(_sharedexception *exc) +{ + _sharedexception_clear(exc); PyMem_Free(exc); } static _sharedexception * -_get_shared_exception(void) +_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) { - _sharedexception *err = PyMem_NEW(_sharedexception, 1); + assert(exctype != NULL); + char *failure = NULL; + + _sharedexception *err = _sharedexception_new(); if (err == NULL) { - return NULL; + goto finally; } - PyObject *exc; - PyObject *value; - PyObject *tb; - PyErr_Fetch(&exc, &value, &tb); - PyObject *msg; - if (value == NULL) { - msg = PyUnicode_FromFormat("%S", exc); + + PyObject *name = PyUnicode_FromFormat("%S", exctype); + if (name == NULL) { + failure = "unable to format exception type name"; + goto finally; } - else { - msg = PyUnicode_FromFormat("%S: %S", exc, value); + err->name = _copy_raw_string(name); + if (err->name == NULL) { + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + failure = "out of memory copying exception type name"; + } + failure = "unable to encode and copy exception type name"; + goto finally; } - if (msg == NULL) { - err->msg = "unable to format exception"; - return err; + + if (exc != NULL) { + PyObject *msg = PyUnicode_FromFormat("%S", exc); + if (msg == NULL) { + failure = "unable to format exception message"; + goto finally; + } + err->msg = _copy_raw_string(msg); + Py_DECREF(msg); + if (err->msg == NULL) { + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + failure = "out of memory copying exception message"; + } + failure = "unable to encode and copy exception message"; + goto finally; + } } - err->msg = _copy_raw_string(msg); - Py_DECREF(msg); - if (err->msg == NULL) { - if (PyErr_ExceptionMatches(PyExc_MemoryError)) { - err->msg = "MemoryError: out of memory copying error message"; +finally: + if (failure != NULL) { + PyErr_Clear(); + if (err->name != NULL) { + PyMem_Free(err->name); + err->name = NULL; } - err->msg = "unable to encode and copy exception message"; + err->msg = failure; } return err; } @@ -260,9 +303,22 @@ interp_exceptions_init(PyObject *ns) } static void -_apply_shared_exception(_sharedexception *exc) +_sharedexception_apply(_sharedexception *exc) { - PyErr_SetString(RunFailedError, exc->msg); + if (exc->name != NULL) { + if (exc->msg != NULL) { + PyErr_Format(RunFailedError, "%s: %s", exc->name, exc->msg); + } + else { + PyErr_SetString(RunFailedError, exc->name); + } + } + else if (exc->msg != NULL) { + PyErr_SetString(RunFailedError, exc->msg); + } + else { + PyErr_SetNone(RunFailedError); + } } /* channel-specific code */ @@ -1475,6 +1531,10 @@ static int _run_script(PyInterpreterState *interp, const char *codestr, _sharedns *shared, _sharedexception **exc) { + PyObject *exctype = NULL; + PyObject *excval = NULL; + PyObject *tb = NULL; + PyObject *main_mod = PyMapping_GetItemString(interp->modules, "__main__"); if (main_mod == NULL) { goto error; @@ -1504,10 +1564,27 @@ _run_script(PyInterpreterState *interp, const char *codestr, Py_DECREF(result); // We throw away the result. } + *exc = NULL; return 0; error: - *exc = _get_shared_exception(); + PyErr_Fetch(&exctype, &excval, &tb); + Py_INCREF(exctype); + Py_XINCREF(excval); + Py_XINCREF(tb); PyErr_Clear(); + + _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb); + Py_DECREF(exctype); + Py_XDECREF(excval); + Py_XDECREF(tb); + if (sharedexc == NULL) { + fprintf(stderr, "RunFailedError: script raised an uncaught exception"); + PyErr_Clear(); + } + else { + assert(!PyErr_Occurred()); + *exc = sharedexc; + } return -1; } @@ -1539,7 +1616,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, // Propagate any exception out to the caller. if (exc != NULL) { - _apply_shared_exception(exc); + _sharedexception_apply(exc); _sharedexception_free(exc); } else if (result != 0) { From f0d44300e2cbc89338aa8292b53dd4be6fdb7706 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 01:04:09 +0000 Subject: [PATCH 12/19] Clean up _PyChannelState memory ops. --- Modules/_xxsubinterpretersmodule.c | 469 +++++++++++++++++++---------- 1 file changed, 311 insertions(+), 158 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 3e1abf635576bd..f39068b2131b98 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -321,7 +321,7 @@ _sharedexception_apply(_sharedexception *exc) } } -/* channel-specific code */ +/* channel-specific code ****************************************************/ static PyObject *ChannelError; static PyObject *ChannelNotFoundError; @@ -376,6 +376,139 @@ channel_exceptions_init(PyObject *ns) return 0; } +/* the channel queue */ + +struct _channelitem; + +typedef struct _channelitem { + _PyCrossInterpreterData *data; + struct _channelitem *next; +} _channelitem; + +static _channelitem * +_channelitem_new(void) +{ + _channelitem *item = PyMem_NEW(_channelitem, 1); + if (item == NULL) { + PyErr_NoMemory(); + return NULL; + } + item->data = NULL; + item->next = NULL; + return item; +} + +static void +_channelitem_clear(_channelitem *item) +{ + if (item->data != NULL) { + _PyCrossInterpreterData_Release(item->data); + PyMem_Free(item->data); + item->data = NULL; + } + item->next = NULL; +} + +static void +_channelitem_free(_channelitem *item) +{ + _channelitem_clear(item); + PyMem_Free(item); +} + +static void +_channelitem_free_all(_channelitem *item) +{ + while (item != NULL) { + _channelitem *last = item; + item = item->next; + _channelitem_free(last); + } +} + +static _PyCrossInterpreterData * +_channelitem_popped(_channelitem *item) +{ + _PyCrossInterpreterData *data = item->data; + item->data = NULL; + _channelitem_free(item); + return data; +} + +typedef struct _channelqueue { + int64_t count; + _channelitem *first; + _channelitem *last; +} _channelqueue; + +static _channelqueue * +_channelqueue_new(void) +{ + _channelqueue *queue = PyMem_NEW(_channelqueue, 1); + if (queue == NULL) { + PyErr_NoMemory(); + return NULL; + } + queue->count = 0; + queue->first = NULL; + queue->last = NULL; + return queue; +} + +static void +_channelqueue_clear(_channelqueue *queue) +{ + _channelitem_free_all(queue->first); + queue->count = 0; + queue->first = NULL; + queue->last = NULL; +} + +static void +_channelqueue_free(_channelqueue *queue) +{ + _channelqueue_clear(queue); + PyMem_Free(queue); +} + +static int +_channelqueue_put(_channelqueue *queue, _PyCrossInterpreterData *data) +{ + _channelitem *item = _channelitem_new(); + if (item == NULL) { + return -1; + } + item->data = data; + + queue->count += 1; + if (queue->first == NULL) { + queue->first = item; + } + else { + queue->last->next = item; + } + queue->last = item; + return 0; +} + +static _PyCrossInterpreterData * +_channelqueue_get(_channelqueue *queue) +{ + _channelitem *item = queue->first; + if (item == NULL) { + return NULL; + } + queue->first = item->next; + if (queue->last == item) { + queue->last = NULL; + } + queue->count -= 1; + + return _channelitem_popped(item); +} + +/* channel-interpreter associations */ + struct _channelend; typedef struct _channelend { @@ -389,24 +522,28 @@ _channelend_new(int64_t interp) { _channelend *end = PyMem_NEW(_channelend, 1); if (end == NULL) { + PyErr_NoMemory(); return NULL; } - end->next = NULL; end->interp = interp; - end->open = 1; - return end; } +static void +_channelend_free(_channelend *end) +{ + PyMem_Free(end); +} + static void _channelend_free_all(_channelend *end) { while (end != NULL) { _channelend *last = end; end = end->next; - PyMem_Free(last); + _channelend_free(last); } } @@ -428,24 +565,7 @@ _channelend_find(_channelend *first, int64_t interp, _channelend **pprev) return end; } -struct _channelitem; - -typedef struct _channelitem { - _PyCrossInterpreterData *data; - struct _channelitem *next; -} _channelitem; - -struct _channel; - -typedef struct _channel { - PyThread_type_lock mutex; - - int open; - - int64_t count; - _channelitem *first; - _channelitem *last; - +typedef struct _channelassociations { // Note that the list entries are never removed for interpreter // for which the channel is closed. This should be a problem in // practice. Also, a channel isn't automatically closed when an @@ -454,39 +574,43 @@ typedef struct _channel { int64_t numrecvopen; _channelend *send; _channelend *recv; -} _PyChannelState; +} _channelends; -static _PyChannelState * -_channel_new(void) +static _channelends * +_channelends_new(void) { - _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1); - if (chan == NULL) { - return NULL; - } - chan->mutex = PyThread_allocate_lock(); - if (chan->mutex == NULL) { - PyMem_Free(chan); - PyErr_SetString(ChannelError, - "can't initialize mutex for new channel"); + _channelends *ends = PyMem_NEW(_channelends, 1); + if (ends== NULL) { return NULL; } + ends->numsendopen = 0; + ends->numrecvopen = 0; + ends->send = NULL; + ends->recv = NULL; + return ends; +} - chan->open = 1; - - chan->count = 0; - chan->first = NULL; - chan->last = NULL; +static void +_channelends_clear(_channelends *ends) +{ + _channelend_free_all(ends->send); + ends->send = NULL; + ends->numsendopen = 0; - chan->numsendopen = 0; - chan->numrecvopen = 0; - chan->send = NULL; - chan->recv = NULL; + _channelend_free_all(ends->recv); + ends->recv = NULL; + ends->numrecvopen = 0; +} - return chan; +static void +_channelends_free(_channelends *ends) +{ + _channelends_clear(ends); + PyMem_Free(ends); } static _channelend * -_channel_add_end(_PyChannelState *chan, _channelend *prev, int64_t interp, +_channelends_add(_channelends *ends, _channelend *prev, int64_t interp, int send) { _channelend *end = _channelend_new(interp); @@ -496,137 +620,163 @@ _channel_add_end(_PyChannelState *chan, _channelend *prev, int64_t interp, if (prev == NULL) { if (send) { - chan->send = end; + ends->send = end; } else { - chan->recv = end; + ends->recv = end; } } else { prev->next = end; } if (send) { - chan->numsendopen += 1; + ends->numsendopen += 1; } else { - chan->numrecvopen += 1; + ends->numrecvopen += 1; } return end; } -static _channelend * -_channel_associate_end(_PyChannelState *chan, int64_t interp, int send) +static int +_channelends_associate(_channelends *ends, int64_t interp, int send) { - if (!chan->open) { - PyErr_SetString(ChannelClosedError, "channel closed"); - return NULL; - } - _channelend *prev; - _channelend *end = _channelend_find(send ? chan->send : chan->recv, + _channelend *end = _channelend_find(send ? ends->send : ends->recv, interp, &prev); if (end != NULL) { if (!end->open) { PyErr_SetString(ChannelClosedError, "channel already closed"); - return NULL; + return -1; } // already associated - return end; + return 0; + } + if (_channelends_add(ends, prev, interp, send) == NULL) { + return -1; + } + return 0; +} + +static int +_channelends_is_open(_channelends *ends) +{ + if (ends->numsendopen != 0 || ends->numrecvopen != 0) { + return 1; + } + if (ends->send == NULL && ends->recv == NULL) { + return 1; } - return _channel_add_end(chan, prev, interp, send); + return 0; } static void -_channel_close_channelend(_PyChannelState *chan, _channelend *end, int send) +_channelends_close_end(_channelends *ends, _channelend *end, int send) { end->open = 0; if (send) { - chan->numsendopen -= 1; + ends->numsendopen -= 1; } else { - chan->numrecvopen -= 1; + ends->numrecvopen -= 1; } } static int -_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int which) +_channelends_close_interpreter(_channelends *ends, int64_t interp, int which) { - PyThread_acquire_lock(chan->mutex, WAIT_LOCK); - - int res = -1; - if (!chan->open) { - PyErr_SetString(ChannelClosedError, "channel already closed"); - goto done; - } - _channelend *prev; _channelend *end; if (which >= 0) { // send/both - end = _channelend_find(chan->send, interp, &prev); + end = _channelend_find(ends->send, interp, &prev); if (end == NULL) { // never associated so add it - end = _channel_add_end(chan, prev, interp, 1); + end = _channelends_add(ends, prev, interp, 1); if (end == NULL) { - goto done; + return -1; } } - _channel_close_channelend(chan, end, 1); + _channelends_close_end(ends, end, 1); } if (which <= 0) { // recv/both - end = _channelend_find(chan->recv, interp, &prev); + end = _channelend_find(ends->recv, interp, &prev); if (end == NULL) { // never associated so add it - end = _channel_add_end(chan, prev, interp, 0); + end = _channelends_add(ends, prev, interp, 0); if (end == NULL) { - goto done; + return -1; } } - _channel_close_channelend(chan, end, 0); + _channelends_close_end(ends, end, 0); } - - if (chan->numsendopen == 0 && chan->numrecvopen == 0) { - if (chan->send != NULL || chan->recv != NULL) { - chan->open = 0; - } - } - - res = 0; -done: - PyThread_release_lock(chan->mutex); - return res; + return 0; } -static int -_channel_close_all(_PyChannelState *chan) +static void +_channelends_close_all(_channelends *ends) { - int res = -1; - PyThread_acquire_lock(chan->mutex, WAIT_LOCK); + // Ensure all the "send"-associated interpreters are closed. + _channelend *end; + for (end = ends->send; end != NULL; end = end->next) { + _channelends_close_end(ends, end, 1); + } - if (!chan->open) { - PyErr_SetString(ChannelClosedError, "channel already closed"); - goto done; + // Ensure all the "recv"-associated interpreters are closed. + for (end = ends->recv; end != NULL; end = end->next) { + _channelends_close_end(ends, end, 0); } +} - chan->open = 0; +/* channels */ - // We *could* also just leave these in place, since we've marked - // the channel as closed already. +struct _channel; - // Ensure all the "send"-associated interpreters are closed. - _channelend *end; - for (end = chan->send; end != NULL; end = end->next) { - _channel_close_channelend(chan, end, 1); - } +typedef struct _channel { + PyThread_type_lock mutex; + _channelqueue *queue; + _channelends *ends; + int open; +} _PyChannelState; - // Ensure all the "recv"-associated interpreters are closed. - for (end = chan->recv; end != NULL; end = end->next) { - _channel_close_channelend(chan, end, 0); +static _PyChannelState * +_channel_new(void) +{ + _PyChannelState *chan = PyMem_NEW(_PyChannelState, 1); + if (chan == NULL) { + return NULL; } + chan->mutex = PyThread_allocate_lock(); + if (chan->mutex == NULL) { + PyMem_Free(chan); + PyErr_SetString(ChannelError, + "can't initialize mutex for new channel"); + return NULL; + } + chan->queue = _channelqueue_new(); + if (chan->queue == NULL) { + PyMem_Free(chan); + return NULL; + } + chan->ends = _channelends_new(); + if (chan->ends == NULL) { + _channelqueue_free(chan->queue); + PyMem_Free(chan); + return NULL; + } + chan->open = 1; + return chan; +} - res = 0; -done: +static void +_channel_free(_PyChannelState *chan) +{ + PyThread_acquire_lock(chan->mutex, WAIT_LOCK); + _channelqueue_free(chan->queue); + _channelends_free(chan->ends); PyThread_release_lock(chan->mutex); - return res; + + PyThread_free_lock(chan->mutex); + PyMem_Free(chan); } static int @@ -634,27 +784,19 @@ _channel_add(_PyChannelState *chan, int64_t interp, _PyCrossInterpreterData *data) { int res = -1; - PyThread_acquire_lock(chan->mutex, WAIT_LOCK); - if (_channel_associate_end(chan, interp, 1) == NULL) { + + if (!chan->open) { + PyErr_SetString(ChannelClosedError, "channel closed"); goto done; } - - _channelitem *item = PyMem_NEW(_channelitem, 1); - if (item == NULL) { + if (_channelends_associate(chan->ends, interp, 1) != 0) { goto done; } - item->data = data; - item->next = NULL; - chan->count += 1; - if (chan->first == NULL) { - chan->first = item; - } - else { - chan->last->next = item; + if (_channelqueue_put(chan->queue, data) != 0) { + goto done; } - chan->last = item; res = 0; done: @@ -668,56 +810,67 @@ _channel_next(_PyChannelState *chan, int64_t interp) _PyCrossInterpreterData *data = NULL; PyThread_acquire_lock(chan->mutex, WAIT_LOCK); - if (_channel_associate_end(chan, interp, 0) == NULL) { + if (!chan->open) { + PyErr_SetString(ChannelClosedError, "channel closed"); goto done; } - - _channelitem *item = chan->first; - if (item == NULL) { + if (_channelends_associate(chan->ends, interp, 0) != 0) { goto done; } - chan->first = item->next; - if (chan->last == item) { - chan->last = NULL; - } - chan->count -= 1; - - data = item->data; - PyMem_Free(item); + data = _channelqueue_get(chan->queue); done: PyThread_release_lock(chan->mutex); return data; } -static void -_channel_clear(_PyChannelState *chan) +static int +_channel_close_interpreter(_PyChannelState *chan, int64_t interp, int which) { - _channelitem *item = chan->first; - while (item != NULL) { - _PyCrossInterpreterData_Release(item->data); - PyMem_Free(item->data); - _channelitem *last = item; - item = item->next; - PyMem_Free(last); + PyThread_acquire_lock(chan->mutex, WAIT_LOCK); + + int res = -1; + if (!chan->open) { + PyErr_SetString(ChannelClosedError, "channel already closed"); + goto done; } - chan->first = NULL; - chan->last = NULL; + + if (_channelends_close_interpreter(chan->ends, interp, which) != 0) { + goto done; + } + chan->open = _channelends_is_open(chan->ends); + + res = 0; +done: + PyThread_release_lock(chan->mutex); + return res; } -static void -_channel_free(_PyChannelState *chan) +static int +_channel_close_all(_PyChannelState *chan) { + int res = -1; PyThread_acquire_lock(chan->mutex, WAIT_LOCK); - _channel_clear(chan); - _channelend_free_all(chan->send); - _channelend_free_all(chan->recv); - PyThread_release_lock(chan->mutex); - PyThread_free_lock(chan->mutex); - PyMem_Free(chan); + if (!chan->open) { + PyErr_SetString(ChannelClosedError, "channel already closed"); + goto done; + } + + chan->open = 0; + + // We *could* also just leave these in place, since we've marked + // the channel as closed already. + _channelends_close_all(chan->ends); + + res = 0; +done: + PyThread_release_lock(chan->mutex); + return res; } +/* the set of channels */ + struct _channelref; typedef struct _channelref { From 4802046131d18a4a8294fcde4349f25dccf09085 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 01:23:36 +0000 Subject: [PATCH 13/19] Add _channelref_free(). --- Modules/_xxsubinterpretersmodule.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index f39068b2131b98..0cd595835832f5 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -894,6 +894,22 @@ _channelref_new(int64_t id, _PyChannelState *chan) return ref; } +//static void +//_channelref_clear(_channelref *ref) +//{ +// ref->id = -1; +// ref->chan = NULL; +// ref->next = NULL; +// ref->objcount = 0; +//} + +static void +_channelref_free(_channelref *ref) +{ + //_channelref_clear(ref); + PyMem_Free(ref); +} + static _channelref * _channelref_find(_channelref *first, int64_t id, _channelref **pprev) { @@ -925,7 +941,6 @@ _channels_init(_channels *channels) if (channels->mutex == NULL) { channels->mutex = PyThread_allocate_lock(); if (channels->mutex == NULL) { - PyMem_Free(channels); PyErr_SetString(ChannelError, "can't initialize mutex for channel management"); return -1; @@ -1061,7 +1076,7 @@ _channels_remove_ref(_channels *channels, _channelref *ref, _channelref *prev, if (pchan != NULL) { *pchan = ref->chan; } - PyMem_Free(ref); + _channelref_free(ref); } static int From ac7bad55356103302af46255bc00bdba497a4860 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 01:50:05 +0000 Subject: [PATCH 14/19] Move the RunFailedError definition down. --- Modules/_xxsubinterpretersmodule.c | 62 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 0cd595835832f5..e35dfe0b0c1830 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -64,6 +64,7 @@ _coerce_id(PyObject *id) return cid; } + /* data-sharing-specific code ***********************************************/ struct _sharednsitem { @@ -282,45 +283,26 @@ _sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) return err; } -static PyObject * RunFailedError; - -static int -interp_exceptions_init(PyObject *ns) -{ - // XXX Move the exceptions into per-module memory? - - // An uncaught exception came out of interp_run_string(). - RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError", - PyExc_RuntimeError, NULL); - if (RunFailedError == NULL) { - return -1; - } - if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) { - return -1; - } - - return 0; -} - static void -_sharedexception_apply(_sharedexception *exc) +_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass) { if (exc->name != NULL) { if (exc->msg != NULL) { - PyErr_Format(RunFailedError, "%s: %s", exc->name, exc->msg); + PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg); } else { - PyErr_SetString(RunFailedError, exc->name); + PyErr_SetString(wrapperclass, exc->name); } } else if (exc->msg != NULL) { - PyErr_SetString(RunFailedError, exc->msg); + PyErr_SetString(wrapperclass, exc->msg); } else { - PyErr_SetNone(RunFailedError); + PyErr_SetNone(wrapperclass); } } + /* channel-specific code ****************************************************/ static PyObject *ChannelError; @@ -1639,7 +1621,30 @@ static PyTypeObject ChannelIDtype = { NULL, /* tp_new */ }; -/* interpreter-specific functions *******************************************/ + +/* interpreter-specific code ************************************************/ + +static PyObject * RunFailedError = NULL; + +static int +interp_exceptions_init(PyObject *ns) +{ + // XXX Move the exceptions into per-module memory? + + if (RunFailedError == NULL) { + // An uncaught exception came out of interp_run_string(). + RunFailedError = PyErr_NewException("_xxsubinterpreters.RunFailedError", + PyExc_RuntimeError, NULL); + if (RunFailedError == NULL) { + return -1; + } + if (PyDict_SetItemString(ns, "RunFailedError", RunFailedError) != 0) { + return -1; + } + } + + return 0; +} static PyInterpreterState * _look_up(PyObject *requested_id) @@ -1748,11 +1753,12 @@ _run_script(PyInterpreterState *interp, const char *codestr, if (sharedexc == NULL) { fprintf(stderr, "RunFailedError: script raised an uncaught exception"); PyErr_Clear(); + sharedexc = NULL; } else { assert(!PyErr_Occurred()); - *exc = sharedexc; } + *exc = sharedexc; return -1; } @@ -1784,7 +1790,7 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, // Propagate any exception out to the caller. if (exc != NULL) { - _sharedexception_apply(exc); + _sharedexception_apply(exc, RunFailedError); _sharedexception_free(exc); } else if (result != 0) { From 0689a9ceebde5645f41fe887efd8a48028ad40f7 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 03:36:06 +0000 Subject: [PATCH 15/19] Do not INCREF after PyErr_Fetch(). --- Modules/_xxsubinterpretersmodule.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index e35dfe0b0c1830..c0251cbd695356 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1739,15 +1739,12 @@ _run_script(PyInterpreterState *interp, const char *codestr, *exc = NULL; return 0; + error: PyErr_Fetch(&exctype, &excval, &tb); - Py_INCREF(exctype); - Py_XINCREF(excval); - Py_XINCREF(tb); - PyErr_Clear(); _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb); - Py_DECREF(exctype); + Py_XDECREF(exctype); Py_XDECREF(excval); Py_XDECREF(tb); if (sharedexc == NULL) { From 9a91a287dbfb78520b0f3adfeefb0112d522fb93 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 03:36:30 +0000 Subject: [PATCH 16/19] DECREF the exception name. --- Modules/_xxsubinterpretersmodule.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index c0251cbd695356..7949b1cf9f4c5c 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -246,6 +246,7 @@ _sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) goto finally; } err->name = _copy_raw_string(name); + Py_DECREF(name); if (err->name == NULL) { if (PyErr_ExceptionMatches(PyExc_MemoryError)) { failure = "out of memory copying exception type name"; From 654e59adb98d96da4d6282617d7bd99d3d6e5e47 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 04:00:51 +0000 Subject: [PATCH 17/19] Free the channel when we close it. --- Modules/_xxsubinterpretersmodule.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 7949b1cf9f4c5c..c8026934f39e33 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1035,6 +1035,9 @@ _channels_close(_channels *channels, int64_t cid, _PyChannelState **pchan) if (pchan != NULL) { *pchan = ref->chan; } + else { + _channel_free(ref->chan); + } ref->chan = NULL; } From 8ca3c9691db0a4412c9480cc72722958d3d2af66 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 04:14:29 +0000 Subject: [PATCH 18/19] Free the data when we are done with it. --- Modules/_xxsubinterpretersmodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index c8026934f39e33..ca208b626a181c 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1260,6 +1260,7 @@ _channel_recv(_channels *channels, int64_t id) return NULL; } _PyCrossInterpreterData_Release(data); + PyMem_Free(data); return obj; } @@ -1281,7 +1282,7 @@ _channel_drop(_channels *channels, int64_t id, int send, int recv) // Past this point we are responsible for releasing the mutex. // Close one or both of the two ends. - int res =_channel_close_interpreter(chan, interp->id, send-recv); + int res = _channel_close_interpreter(chan, interp->id, send-recv); PyThread_release_lock(mutex); return res; } From 702876b9fee86bd328921a2b0ebae0c69ed60002 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Sat, 3 Feb 2018 04:22:38 +0000 Subject: [PATCH 19/19] DECREF the ID in channelid_hash(). --- Modules/_xxsubinterpretersmodule.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index ca208b626a181c..7829b4cd951156 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1464,7 +1464,9 @@ channelid_hash(PyObject *self) if (id == NULL) { return -1; } - return PyObject_Hash(id); + Py_hash_t hash = PyObject_Hash(id); + Py_DECREF(id); + return hash; } static PyObject * pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy