bpo-38005: Fixed comparing and creating of InterpreterID and ChannelID. (GH-15652)

* Fix a crash in comparing with float (and maybe other crashes).
* They are now never equal to strings and non-integer numbers.
* Comparison with a large number no longer raises OverflowError.
* Arbitrary exceptions no longer silenced in constructors and comparisons.
* TypeError raised in the constructor contains now the name of the type.
* Accept only ChannelID and int-like objects in channel functions.
* Accept only InterpreterId, int-like objects and str in the InterpreterId constructor.
* Accept int-like objects, not just int in interpreter related functions.
This commit is contained in:
Serhiy Storchaka 2019-09-13 22:50:27 +03:00 committed by GitHub
parent e082e7cbe4
commit bf169915ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 153 additions and 177 deletions

View file

@ -5,38 +5,6 @@
#include "interpreteridobject.h"
int64_t
_Py_CoerceID(PyObject *orig)
{
PyObject *pyid = PyNumber_Long(orig);
if (pyid == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
PyErr_Format(PyExc_TypeError,
"'id' must be a non-negative int, got %R", orig);
}
else {
PyErr_Format(PyExc_ValueError,
"'id' must be a non-negative int, got %R", orig);
}
return -1;
}
int64_t id = PyLong_AsLongLong(pyid);
Py_DECREF(pyid);
if (id == -1 && PyErr_Occurred() != NULL) {
if (!PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyErr_Format(PyExc_ValueError,
"'id' must be a non-negative int, got %R", orig);
}
return -1;
}
if (id < 0) {
PyErr_Format(PyExc_ValueError,
"'id' must be a non-negative int, got %R", orig);
return -1;
}
return id;
}
typedef struct interpid {
PyObject_HEAD
int64_t id;
@ -85,8 +53,31 @@ interpid_new(PyTypeObject *cls, PyObject *args, PyObject *kwds)
id = ((interpid *)idobj)->id;
}
else {
id = _Py_CoerceID(idobj);
PyObject *pyid;
if (PyIndex_Check(idobj)) {
pyid = idobj;
Py_INCREF(pyid);
}
else if (PyUnicode_Check(idobj)) {
pyid = PyNumber_Long(idobj);
if (pyid == NULL) {
return NULL;
}
}
else {
PyErr_Format(PyExc_TypeError,
"interpreter ID must be an int, got %.100s",
idobj->ob_type->tp_name);
return NULL;
}
id = PyLong_AsLongLong(pyid);
Py_DECREF(pyid);
if (id == -1 && PyErr_Occurred()) {
return NULL;
}
if (id < 0) {
PyErr_Format(PyExc_ValueError,
"interpreter ID must be a non-negative int, got %R", idobj);
return NULL;
}
}
@ -202,23 +193,26 @@ interpid_richcompare(PyObject *self, PyObject *other, int op)
interpid *otherid = (interpid *)other;
equal = (id->id == otherid->id);
}
else {
other = PyNumber_Long(other);
if (other == NULL) {
PyErr_Clear();
Py_RETURN_NOTIMPLEMENTED;
}
int64_t otherid = PyLong_AsLongLong(other);
Py_DECREF(other);
if (otherid == -1 && PyErr_Occurred() != NULL) {
else if (PyLong_CheckExact(other)) {
/* Fast path */
int overflow;
long long otherid = PyLong_AsLongLongAndOverflow(other, &overflow);
if (otherid == -1 && PyErr_Occurred()) {
return NULL;
}
if (otherid < 0) {
equal = 0;
}
else {
equal = (id->id == otherid);
equal = !overflow && (otherid >= 0) && (id->id == otherid);
}
else if (PyNumber_Check(other)) {
PyObject *pyid = PyLong_FromLongLong(id->id);
if (pyid == NULL) {
return NULL;
}
PyObject *res = PyObject_RichCompare(pyid, other, op);
Py_DECREF(pyid);
return res;
}
else {
Py_RETURN_NOTIMPLEMENTED;
}
if ((op == Py_EQ && equal) || (op == Py_NE && !equal)) {
@ -250,8 +244,7 @@ PyTypeObject _PyInterpreterID_Type = {
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
interpid_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
@ -262,7 +255,7 @@ PyTypeObject _PyInterpreterID_Type = {
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyLong_Type, /* tp_base */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
@ -297,12 +290,17 @@ _PyInterpreterID_LookUp(PyObject *requested_id)
if (PyObject_TypeCheck(requested_id, &_PyInterpreterID_Type)) {
id = ((interpid *)requested_id)->id;
}
else {
else if (PyIndex_Check(requested_id)) {
id = PyLong_AsLongLong(requested_id);
if (id == -1 && PyErr_Occurred() != NULL) {
return NULL;
}
assert(id <= INT64_MAX);
}
else {
PyErr_Format(PyExc_TypeError, "interpreter ID must be an int, got %.100s",
requested_id->ob_type->tp_name);
return NULL;
}
return _PyInterpreterState_LookUpID(id);
}