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:
Tim Peters 2003-04-13 22:13:08 +00:00
parent d39078ba2d
commit 874e1f7ed3
1 changed files with 50 additions and 31 deletions

View File

@ -1319,61 +1319,76 @@ static PyObject *
handle_range_longs(PyObject *self, PyObject *args)
{
PyObject *ilow;
PyObject *ihigh;
PyObject *zero = NULL;
PyObject *ihigh = NULL;
PyObject *istep = NULL;
PyObject *curnum = NULL;
PyObject *v = NULL;
long bign;
int i, n;
int cmp_result;
zero = PyLong_FromLong(0L);
PyObject *zero = PyLong_FromLong(0);
if (zero == NULL)
return NULL;
ilow = zero; /* Default lower bound */
if (!PyArg_ParseTuple(args, "O", &ihigh, &istep)) {
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;
if (!PyArg_UnpackTuple(args, "range", 1, 3, &ilow, &ihigh, &istep)) {
Py_DECREF(zero);
return NULL;
}
if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) {
PyErr_SetString(PyExc_ValueError,
"integer end argument expected, got float.");
goto Fail;
return NULL;
/* Figure out which way we were called, supply defaults, and be
* sure to incref everything so that the decrefs at the end
* are correct.
*/
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) {
istep = PyLong_FromLong(1L);
if (istep == NULL)
goto Fail;
}
else {
if (!PyInt_Check(istep) && !PyLong_Check(istep)) {
PyErr_SetString(PyExc_ValueError,
"integer step argument expected, got float.");
goto Fail;
}
Py_INCREF(istep);
}
if (PyObject_Cmp(istep, zero, &cmp_result) == -1) {
/* 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)) {
PyErr_SetString(PyExc_ValueError,
"integer step argument expected, got float.");
goto Fail;
}
if (PyObject_Cmp(istep, zero, &cmp_result) == -1)
goto Fail;
if (cmp_result == 0) {
PyErr_SetString(PyExc_ValueError,
"range() arg 3 must not be zero");
@ -1419,15 +1434,19 @@ handle_range_longs(PyObject *self, PyObject *args)
Py_DECREF(curnum);
curnum = tmp_num;
}
Py_DECREF(curnum);
Py_DECREF(ilow);
Py_DECREF(ihigh);
Py_DECREF(istep);
Py_DECREF(zero);
Py_DECREF(curnum);
return v;
Fail:
Py_XDECREF(curnum);
Py_DECREF(ilow);
Py_DECREF(ihigh);
Py_XDECREF(istep);
Py_XDECREF(zero);
Py_DECREF(zero);
Py_XDECREF(curnum);
Py_XDECREF(v);
return NULL;
}