diff options
| author | Neil Schemenauer <nascheme@enme.ucalgary.ca> | 2002-12-30 20:18:15 +0000 | 
|---|---|---|
| committer | Neil Schemenauer <nascheme@enme.ucalgary.ca> | 2002-12-30 20:18:15 +0000 | 
| commit | d4b0fea43a8655d15562fa42d56def93fe2348ef (patch) | |
| tree | 91bf92c7a3eaaef0e55302f8e558eb7d2189ba3a /Objects | |
| parent | 6005a344ce9938256e0e8bb986ebad29c449f3c6 (diff) | |
| download | cpython-git-d4b0fea43a8655d15562fa42d56def93fe2348ef.tar.gz | |
Always try nb_* slots before trying sq_concat, sq_inplace_concat, sq_repeat,
andsq_inplace_repeat.  This fixes a number of corner case bugs (see #624807).
Consolidate the int and long sequence repeat code.  Before the change, integers
checked for integer overflow but longs did not.
Diffstat (limited to 'Objects')
| -rw-r--r-- | Objects/abstract.c | 178 | 
1 files changed, 128 insertions, 50 deletions
| diff --git a/Objects/abstract.c b/Objects/abstract.c index 8389774e2f..4ac73422dc 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -405,18 +405,23 @@ binary_op1(PyObject *v, PyObject *w, const int op_slot)  }  static PyObject * +binop_type_error(PyObject *v, PyObject *w, const char *op_name) +{ +	PyErr_Format(PyExc_TypeError, +		     "unsupported operand type(s) for %s: '%s' and '%s'", +		     op_name, +		     v->ob_type->tp_name, +		     w->ob_type->tp_name); +	return NULL; +} + +static PyObject *  binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)  {  	PyObject *result = binary_op1(v, w, op_slot);  	if (result == Py_NotImplemented) { -		Py_DECREF(Py_NotImplemented); -		PyErr_Format( -			PyExc_TypeError, -			"unsupported operand type(s) for %s: '%s' and '%s'", -			op_name, -			v->ob_type->tp_name, -			w->ob_type->tp_name); -		return NULL; +		Py_DECREF(result); +		return binop_type_error(v, w, op_name);  	}  	return result;  } @@ -595,7 +600,6 @@ BINARY_FUNC(PyNumber_And, nb_and, "&")  BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<")  BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>")  BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-") -BINARY_FUNC(PyNumber_Multiply, nb_multiply, "*")  BINARY_FUNC(PyNumber_Divide, nb_divide, "/")  BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()") @@ -611,17 +615,74 @@ PyNumber_Add(PyObject *v, PyObject *w)  		}  		if (result == Py_NotImplemented) {  			Py_DECREF(result); -			PyErr_Format( -			    PyExc_TypeError, -			    "unsupported operand types for +: '%s' and '%s'", -			    v->ob_type->tp_name, -			    w->ob_type->tp_name); -			result = NULL; +			return binop_type_error(v, w, "+");                  }  	}  	return result;  } +static PyObject * +sequence_repeat(intargfunc repeatfunc, PyObject *seq, PyObject *n) +{ +	long count; +	if (PyInt_Check(n)) { +		count  = PyInt_AsLong(n); +	} +	else if (PyLong_Check(n)) { +		count = PyLong_AsLong(n); +		if (count == -1 && PyErr_Occurred()) +			return NULL; +	} +	else { +		return type_error( +			"can't multiply sequence to non-int"); +	} +#if LONG_MAX != INT_MAX +	if (count > INT_MAX) { +		PyErr_SetString(PyExc_ValueError, +				"sequence repeat count too large"); +		return NULL; +	} +	else if (count < INT_MIN) +		count = INT_MIN; +	/* XXX Why don't I either + +	   - set count to -1 whenever it's negative (after all, +	     sequence repeat usually treats negative numbers +	     as zero(); or + +	   - raise an exception when it's less than INT_MIN? + +	   I'm thinking about a hypothetical use case where some +	   sequence type might use a negative value as a flag of +	   some kind.  In those cases I don't want to break the +	   code by mapping all negative values to -1.  But I also +	   don't want to break e.g. []*(-sys.maxint), which is +	   perfectly safe, returning [].  As a compromise, I do +	   map out-of-range negative values. +	*/ +#endif +	return (*repeatfunc)(seq, (int)count); +} + +PyObject * +PyNumber_Multiply(PyObject *v, PyObject *w) +{ +	PyObject *result = binary_op1(v, w, NB_SLOT(nb_multiply)); +	if (result == Py_NotImplemented) { +		PySequenceMethods *mv = v->ob_type->tp_as_sequence; +		PySequenceMethods *mw = w->ob_type->tp_as_sequence; +		if  (mv && mv->sq_repeat) { +			return sequence_repeat(mv->sq_repeat, v, w); +		} +		else if (mw && mw->sq_repeat) { +			return sequence_repeat(mw->sq_repeat, w, v); +		} +		result = binop_type_error(v, w, "*"); +	} +	return result; +} +  PyObject *  PyNumber_FloorDivide(PyObject *v, PyObject *w)  { @@ -668,8 +729,7 @@ PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)  	PyType_HasFeature((t)->ob_type, Py_TPFLAGS_HAVE_INPLACEOPS)  static PyObject * -binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, -		const char *op_name) +binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot)  {  	PyNumberMethods *mv = v->ob_type->tp_as_number;  	if (mv != NULL && HASINPLACE(v)) { @@ -682,7 +742,19 @@ binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,  			Py_DECREF(x);  		}  	} -	return binary_op(v, w, op_slot, op_name); +	return binary_op1(v, w, op_slot); +} + +static PyObject * +binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, +		const char *op_name) +{ +	PyObject *result = binary_iop1(v, w, iop_slot, op_slot); +	if (result == Py_NotImplemented) { +		Py_DECREF(result); +		return binop_type_error(v, w, op_name); +	} +	return result;  }  #define INPLACE_BINOP(func, iop, op, op_name) \ @@ -718,47 +790,53 @@ PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w)  PyObject *  PyNumber_InPlaceAdd(PyObject *v, PyObject *w)  { -	binaryfunc f = NULL; - -	if (v->ob_type->tp_as_sequence != NULL) { -		if (HASINPLACE(v)) -			f = v->ob_type->tp_as_sequence->sq_inplace_concat; -		if (f == NULL) -			f = v->ob_type->tp_as_sequence->sq_concat; -		if (f != NULL) -			return (*f)(v, w); +	PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_add), +				       NB_SLOT(nb_add)); +	if (result == Py_NotImplemented) { +		PySequenceMethods *m = v->ob_type->tp_as_sequence; +		Py_DECREF(result); +		if (m != NULL) { +			binaryfunc f = NULL; +			if (HASINPLACE(v)) +				f = m->sq_inplace_concat; +			if (f == NULL) +				f = m->sq_concat; +			if (f != NULL) +				return (*f)(v, w); +		} +		result = binop_type_error(v, w, "+=");  	} -	return binary_iop(v, w, NB_SLOT(nb_inplace_add), -			  NB_SLOT(nb_add), "+="); +	return result;  }  PyObject *  PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)  { -	PyObject * (*g)(PyObject *, int) = NULL; -	if (HASINPLACE(v) && -	    v->ob_type->tp_as_sequence && -	    (g = v->ob_type->tp_as_sequence->sq_inplace_repeat) && -	    !(v->ob_type->tp_as_number && -	      v->ob_type->tp_as_number->nb_inplace_multiply)) -	{ -		long n; -		if (PyInt_Check(w)) { -			n  = PyInt_AsLong(w); -		} -		else if (PyLong_Check(w)) { -			n = PyLong_AsLong(w); -			if (n == -1 && PyErr_Occurred()) -				return NULL; +	PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_multiply), +				       NB_SLOT(nb_multiply)); +	if (result == Py_NotImplemented) { +		intargfunc f = NULL; +		PySequenceMethods *mv = v->ob_type->tp_as_sequence; +		PySequenceMethods *mw = w->ob_type->tp_as_sequence; +		Py_DECREF(result); +		if (mv != NULL) { +			if (HASINPLACE(v)) +				f = mv->sq_inplace_repeat; +			if (f == NULL) +				f = mv->sq_repeat; +			if (f != NULL) +				return sequence_repeat(f, v, w);  		} -		else { -			return type_error( -				"can't multiply sequence to non-int"); +		else if (mw != NULL) { +			/* Note that the right hand operand should not be +			 * mutated in this case so sq_inplace_repeat is not +			 * used. */ +			if (mw->sq_repeat) +				return sequence_repeat(mw->sq_repeat, w, v);  		} -		return (*g)(v, (int)n); +		result = binop_type_error(v, w, "*=");  	} -	return binary_iop(v, w, NB_SLOT(nb_inplace_multiply), -				NB_SLOT(nb_multiply), "*="); +	return result;  }  PyObject * | 
