mirror of
https://github.com/python/cpython.git
synced 2025-11-03 03:22:27 +00:00
handle_range_longs(): refcount handling is very delicate here, and
the code erroneously decrefed the istep argument in an error case. This caused a co_consts tuple to lose a float constant prematurely, which eventually caused gc to try executing static data in floatobject.c (don't ask <wink>). So reworked this extensively to ensure refcount correctness.
This commit is contained in:
parent
d39078ba2d
commit
874e1f7ed3
1 changed files with 50 additions and 31 deletions
|
|
@ -1319,61 +1319,76 @@ static PyObject *
|
||||||
handle_range_longs(PyObject *self, PyObject *args)
|
handle_range_longs(PyObject *self, PyObject *args)
|
||||||
{
|
{
|
||||||
PyObject *ilow;
|
PyObject *ilow;
|
||||||
PyObject *ihigh;
|
PyObject *ihigh = NULL;
|
||||||
PyObject *zero = NULL;
|
|
||||||
PyObject *istep = NULL;
|
PyObject *istep = NULL;
|
||||||
|
|
||||||
PyObject *curnum = NULL;
|
PyObject *curnum = NULL;
|
||||||
PyObject *v = NULL;
|
PyObject *v = NULL;
|
||||||
long bign;
|
long bign;
|
||||||
int i, n;
|
int i, n;
|
||||||
int cmp_result;
|
int cmp_result;
|
||||||
|
|
||||||
zero = PyLong_FromLong(0L);
|
PyObject *zero = PyLong_FromLong(0);
|
||||||
|
|
||||||
if (zero == NULL)
|
if (zero == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
ilow = zero; /* Default lower bound */
|
if (!PyArg_UnpackTuple(args, "range", 1, 3, &ilow, &ihigh, &istep)) {
|
||||||
if (!PyArg_ParseTuple(args, "O", &ihigh, &istep)) {
|
Py_DECREF(zero);
|
||||||
PyErr_Clear();
|
|
||||||
if (!PyArg_ParseTuple(args,
|
|
||||||
"OO|O;range() requires 1-3 int arguments",
|
|
||||||
&ilow, &ihigh, &istep))
|
|
||||||
goto Fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyInt_Check(ilow) && !PyLong_Check(ilow)) {
|
|
||||||
PyErr_SetString(PyExc_ValueError,
|
|
||||||
"integer start argument expected, got float.");
|
|
||||||
goto Fail;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) {
|
/* Figure out which way we were called, supply defaults, and be
|
||||||
PyErr_SetString(PyExc_ValueError,
|
* sure to incref everything so that the decrefs at the end
|
||||||
"integer end argument expected, got float.");
|
* are correct.
|
||||||
goto Fail;
|
*/
|
||||||
return NULL;
|
assert(ilow != NULL);
|
||||||
|
if (ihigh == NULL) {
|
||||||
|
/* only 1 arg -- it's the upper limit */
|
||||||
|
ihigh = ilow;
|
||||||
|
ilow = NULL;
|
||||||
}
|
}
|
||||||
|
assert(ihigh != NULL);
|
||||||
|
Py_INCREF(ihigh);
|
||||||
|
|
||||||
/* If no istep was supplied, default to 1. */
|
/* ihigh correct now; do ilow */
|
||||||
|
if (ilow == NULL)
|
||||||
|
ilow = zero;
|
||||||
|
Py_INCREF(ilow);
|
||||||
|
|
||||||
|
/* ilow and ihigh correct now; do istep */
|
||||||
if (istep == NULL) {
|
if (istep == NULL) {
|
||||||
istep = PyLong_FromLong(1L);
|
istep = PyLong_FromLong(1L);
|
||||||
if (istep == NULL)
|
if (istep == NULL)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
Py_INCREF(istep);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX What reason do we have to believe that if an arg isn't an
|
||||||
|
* XXX int, it must be a float?
|
||||||
|
*/
|
||||||
|
if (!PyInt_Check(ilow) && !PyLong_Check(ilow)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"integer start argument expected, got float.");
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError,
|
||||||
|
"integer end argument expected, got float.");
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
if (!PyInt_Check(istep) && !PyLong_Check(istep)) {
|
if (!PyInt_Check(istep) && !PyLong_Check(istep)) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"integer step argument expected, got float.");
|
"integer step argument expected, got float.");
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
}
|
||||||
Py_INCREF(istep);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyObject_Cmp(istep, zero, &cmp_result) == -1) {
|
if (PyObject_Cmp(istep, zero, &cmp_result) == -1)
|
||||||
goto Fail;
|
goto Fail;
|
||||||
}
|
|
||||||
|
|
||||||
if (cmp_result == 0) {
|
if (cmp_result == 0) {
|
||||||
PyErr_SetString(PyExc_ValueError,
|
PyErr_SetString(PyExc_ValueError,
|
||||||
"range() arg 3 must not be zero");
|
"range() arg 3 must not be zero");
|
||||||
|
|
@ -1419,15 +1434,19 @@ handle_range_longs(PyObject *self, PyObject *args)
|
||||||
Py_DECREF(curnum);
|
Py_DECREF(curnum);
|
||||||
curnum = tmp_num;
|
curnum = tmp_num;
|
||||||
}
|
}
|
||||||
Py_DECREF(curnum);
|
Py_DECREF(ilow);
|
||||||
|
Py_DECREF(ihigh);
|
||||||
Py_DECREF(istep);
|
Py_DECREF(istep);
|
||||||
Py_DECREF(zero);
|
Py_DECREF(zero);
|
||||||
|
Py_DECREF(curnum);
|
||||||
return v;
|
return v;
|
||||||
|
|
||||||
Fail:
|
Fail:
|
||||||
Py_XDECREF(curnum);
|
Py_DECREF(ilow);
|
||||||
|
Py_DECREF(ihigh);
|
||||||
Py_XDECREF(istep);
|
Py_XDECREF(istep);
|
||||||
Py_XDECREF(zero);
|
Py_DECREF(zero);
|
||||||
|
Py_XDECREF(curnum);
|
||||||
Py_XDECREF(v);
|
Py_XDECREF(v);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue