Commit 8c126f17 authored by Stefan Krah's avatar Stefan Krah

Issue #26974: Fix segfault in the presence of absurd subclassing. Proactively

eliminate all internal uses of overridden methods.
parent 80ab069f
......@@ -5398,6 +5398,34 @@ class CWhitebox(unittest.TestCase):
y = Decimal(10**(9*25)).__sizeof__()
self.assertEqual(y, x+4)
def test_internal_use_of_overridden_methods(self):
Decimal = C.Decimal
# Unsound subtyping
class X(float):
def as_integer_ratio(self):
return 1
def __abs__(self):
return self
class Y(float):
def __abs__(self):
return [1]*200
class I(int):
def bit_length(self):
return [1]*200
class Z(float):
def as_integer_ratio(self):
return (I(1), I(1))
def __abs__(self):
return self
for cls in X, Y, Z:
self.assertEqual(Decimal.from_float(cls(101.1)),
Decimal.from_float(101.1))
@requires_docstrings
@unittest.skipUnless(C, "test requires C version")
class SignatureTest(unittest.TestCase):
......
......@@ -2208,6 +2208,14 @@ PyDecType_FromLongExact(PyTypeObject *type, const PyObject *pylong,
return dec;
}
/* External C-API functions */
static binaryfunc _py_long_multiply;
static binaryfunc _py_long_floor_divide;
static ternaryfunc _py_long_power;
static unaryfunc _py_float_abs;
static PyCFunction _py_long_bit_length;
static PyCFunction _py_float_as_integer_ratio;
/* Return a PyDecObject or a subtype from a PyFloatObject.
Conversion is exact. */
static PyObject *
......@@ -2258,13 +2266,13 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v,
}
/* absolute value of the float */
tmp = PyObject_CallMethod(v, "__abs__", NULL);
tmp = _py_float_abs(v);
if (tmp == NULL) {
return NULL;
}
/* float as integer ratio: numerator/denominator */
n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL);
n_d = _py_float_as_integer_ratio(tmp, NULL);
Py_DECREF(tmp);
if (n_d == NULL) {
return NULL;
......@@ -2272,7 +2280,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v,
n = PyTuple_GET_ITEM(n_d, 0);
d = PyTuple_GET_ITEM(n_d, 1);
tmp = PyObject_CallMethod(d, "bit_length", NULL);
tmp = _py_long_bit_length(d, NULL);
if (tmp == NULL) {
Py_DECREF(n_d);
return NULL;
......@@ -5511,6 +5519,32 @@ static struct int_constmap int_constants [] = {
#define CHECK_PTR(expr) \
do { if ((expr) == NULL) goto error; } while (0)
static PyCFunction
cfunc_noargs(PyTypeObject *t, const char *name)
{
struct PyMethodDef *m;
if (t->tp_methods == NULL) {
goto error;
}
for (m = t->tp_methods; m->ml_name != NULL; m++) {
if (strcmp(name, m->ml_name) == 0) {
if (!(m->ml_flags & METH_NOARGS)) {
goto error;
}
return m->ml_meth;
}
}
error:
PyErr_Format(PyExc_RuntimeError,
"internal error: could not find method %s", name);
return NULL;
}
PyMODINIT_FUNC
PyInit__decimal(void)
{
......@@ -5535,6 +5569,16 @@ PyInit__decimal(void)
mpd_setminalloc(_Py_DEC_MINALLOC);
/* Init external C-API functions */
_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply;
_py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide;
_py_long_power = PyLong_Type.tp_as_number->nb_power;
_py_float_abs = PyFloat_Type.tp_as_number->nb_absolute;
ASSIGN_PTR(_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type,
"as_integer_ratio"));
ASSIGN_PTR(_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length"));
/* Init types */
PyDec_Type.tp_base = &PyBaseObject_Type;
PyDecContext_Type.tp_base = &PyBaseObject_Type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment