Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 6379913

Browse files
authoredJun 2, 2018
bpo-33615: Re-enable a subinterpreter test. (gh-7251)
For bpo-32604 I added extra subinterpreter-related tests (see #6914), which caused a few buildbots to crash. This patch fixes the crash by ensuring that refcounts in channels are handled properly.
1 parent 29996a1 commit 6379913

File tree

4 files changed

+42
-23
lines changed

4 files changed

+42
-23
lines changed
 

‎Include/internal/pystate.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ struct _xid;
8080

8181
// _PyCrossInterpreterData is similar to Py_buffer as an effectively
8282
// opaque struct that holds data outside the object machinery. This
83-
// is necessary to pass between interpreters in the same process.
83+
// is necessary to pass safely between interpreters in the same process.
8484
typedef struct _xid {
8585
// data is the cross-interpreter-safe derivation of a Python object
8686
// (see _PyObject_GetCrossInterpreterData). It will be NULL if the
@@ -89,8 +89,9 @@ typedef struct _xid {
8989
// obj is the Python object from which the data was derived. This
9090
// is non-NULL only if the data remains bound to the object in some
9191
// way, such that the object must be "released" (via a decref) when
92-
// the data is released. In that case it is automatically
93-
// incref'ed (to match the automatic decref when releaed).
92+
// the data is released. In that case the code that sets the field,
93+
// likely a registered "crossinterpdatafunc", is responsible for
94+
// ensuring it owns the reference (i.e. incref).
9495
PyObject *obj;
9596
// interp is the ID of the owning interpreter of the original
9697
// object. It corresponds to the active interpreter when

‎Lib/test/test__xxsubinterpreters.py

-2
Original file line numberDiff line numberDiff line change
@@ -1315,8 +1315,6 @@ def test_run_string_arg_unresolved(self):
13151315
self.assertEqual(obj, b'spam')
13161316
self.assertEqual(out.strip(), 'send')
13171317

1318-
# XXX Fix the crashes.
1319-
@unittest.skip('bpo-33615: triggering crashes so temporarily disabled')
13201318
def test_run_string_arg_resolved(self):
13211319
cid = interpreters.channel_create()
13221320
cid = interpreters._channel_id(cid, _resolve=True)

‎Modules/_xxsubinterpretersmodule.c

+1
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ _channelid_shared(PyObject *obj, _PyCrossInterpreterData *data)
17121712
xid->resolve = ((channelid *)obj)->resolve;
17131713

17141714
data->data = xid;
1715+
Py_INCREF(obj);
17151716
data->obj = obj;
17161717
data->new_object = _channelid_from_xid;
17171718
data->free = PyMem_Free;

‎Python/pystate.c

+37-18
Original file line numberDiff line numberDiff line change
@@ -1205,7 +1205,6 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
12051205
}
12061206

12071207
// Fill in the blanks and validate the result.
1208-
Py_XINCREF(data->obj);
12091208
data->interp = interp->id;
12101209
if (_check_xidata(data) != 0) {
12111210
_PyCrossInterpreterData_Release(data);
@@ -1215,6 +1214,40 @@ _PyObject_GetCrossInterpreterData(PyObject *obj, _PyCrossInterpreterData *data)
12151214
return 0;
12161215
}
12171216

1217+
static void
1218+
_release_xidata(void *arg)
1219+
{
1220+
_PyCrossInterpreterData *data = (_PyCrossInterpreterData *)arg;
1221+
if (data->free != NULL) {
1222+
data->free(data->data);
1223+
}
1224+
Py_XDECREF(data->obj);
1225+
}
1226+
1227+
static void
1228+
_call_in_interpreter(PyInterpreterState *interp,
1229+
void (*func)(void *), void *arg)
1230+
{
1231+
/* We would use Py_AddPendingCall() if it weren't specific to the
1232+
* main interpreter (see bpo-33608). In the meantime we take a
1233+
* naive approach.
1234+
*/
1235+
PyThreadState *save_tstate = NULL;
1236+
if (interp != PyThreadState_Get()->interp) {
1237+
// XXX Using the "head" thread isn't strictly correct.
1238+
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1239+
// XXX Possible GILState issues?
1240+
save_tstate = PyThreadState_Swap(tstate);
1241+
}
1242+
1243+
func(arg);
1244+
1245+
// Switch back.
1246+
if (save_tstate != NULL) {
1247+
PyThreadState_Swap(save_tstate);
1248+
}
1249+
}
1250+
12181251
void
12191252
_PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
12201253
{
@@ -1233,24 +1266,8 @@ _PyCrossInterpreterData_Release(_PyCrossInterpreterData *data)
12331266
return;
12341267
}
12351268

1236-
PyThreadState *save_tstate = NULL;
1237-
if (interp != PyThreadState_Get()->interp) {
1238-
// XXX Using the "head" thread isn't strictly correct.
1239-
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
1240-
// XXX Possible GILState issues?
1241-
save_tstate = PyThreadState_Swap(tstate);
1242-
}
1243-
12441269
// "Release" the data and/or the object.
1245-
if (data->free != NULL) {
1246-
data->free(data->data);
1247-
}
1248-
Py_XDECREF(data->obj);
1249-
1250-
// Switch back.
1251-
if (save_tstate != NULL) {
1252-
PyThreadState_Swap(save_tstate);
1253-
}
1270+
_call_in_interpreter(interp, _release_xidata, data);
12541271
}
12551272

12561273
PyObject *
@@ -1355,6 +1372,7 @@ _bytes_shared(PyObject *obj, _PyCrossInterpreterData *data)
13551372
return -1;
13561373
}
13571374
data->data = (void *)shared;
1375+
Py_INCREF(obj);
13581376
data->obj = obj; // Will be "released" (decref'ed) when data released.
13591377
data->new_object = _new_bytes_object;
13601378
data->free = PyMem_Free;
@@ -1382,6 +1400,7 @@ _str_shared(PyObject *obj, _PyCrossInterpreterData *data)
13821400
shared->buffer = PyUnicode_DATA(obj);
13831401
shared->len = PyUnicode_GET_LENGTH(obj) - 1;
13841402
data->data = (void *)shared;
1403+
Py_INCREF(obj);
13851404
data->obj = obj; // Will be "released" (decref'ed) when data released.
13861405
data->new_object = _new_str_object;
13871406
data->free = PyMem_Free;

0 commit comments

Comments
 (0)
Please sign in to comment.