Skip to content

Commit afa0238

Browse files
committed
Deal with normalised exceptions correctly
Exceptions retrieved via PyErr_Fetch might be normalised or not. This respectively means that the second argument of PyErr_Fetch will contain the exception object itself (i.e., an instance of StopIteration), or the value that the exception object would contain if actually built (i.e., the result we are interested in). We have always received non-normalised exceptions until now, but we *could* have received normalised ones, so this was a bug that was waiting to happen at some point. More importantly, starting with Python 3.12 exception values returned by PyErr_Fetch and friends are *always* normalised, so the async funcitons of the C backend were not working correctly (because gen->read_func didn't contain a function, but an instance of StopIteration). This commit addresses further problems found while working on #98.
1 parent a5ba8d3 commit afa0238

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

ijson/backends/yajl2_c/async_reading_generator.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,22 @@ static int is_gen_coroutine(PyObject *o)
8383
return 0;
8484
}
8585

86+
static PyObject* value_from_stopiteration()
87+
{
88+
PyObject *ptype, *pvalue, *ptraceback, *return_value;
89+
PyErr_Fetch(&ptype, &pvalue, &ptraceback);
90+
if (PyErr_GivenExceptionMatches(pvalue, PyExc_StopIteration)) {
91+
return_value = PyObject_GetAttrString(pvalue, "value");
92+
Py_XDECREF(pvalue);
93+
}
94+
else {
95+
return_value = pvalue;
96+
}
97+
Py_XDECREF(ptype);
98+
Py_XDECREF(ptraceback);
99+
return return_value;
100+
}
101+
86102
static PyObject *async_reading_generator_next(PyObject *self)
87103
{
88104
async_reading_generator *gen = (async_reading_generator *)self;
@@ -140,19 +156,13 @@ static PyObject *async_reading_generator_next(PyObject *self)
140156

141157
// We await on two things: getting the correct read function (only once),
142158
// and reading from it (many times, self->read_func is set)
143-
PyObject *ptype, *ptraceback;
144159
if (gen->read_func == NULL) {
145-
PyErr_Fetch(&ptype, &gen->read_func, &ptraceback);
146-
Py_XDECREF(ptype);
147-
Py_XDECREF(ptraceback);
160+
gen->read_func = value_from_stopiteration();
148161
Py_RETURN_NONE;
149162
}
150163

151164
// Finished awaiting on read() result, parse it
152-
PyObject *buffer;
153-
PyErr_Fetch(&ptype, &buffer, &ptraceback);
154-
Py_XDECREF(ptype);
155-
Py_XDECREF(ptraceback);
165+
PyObject *buffer = value_from_stopiteration();
156166

157167
Py_buffer view;
158168
N_M1(PyObject_GetBuffer(buffer, &view, PyBUF_SIMPLE));

0 commit comments

Comments
 (0)