mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +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