Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8c126f1

Browse files
author
Stefan Krah
committed
Issue #26974: Fix segfault in the presence of absurd subclassing. Proactively
eliminate all internal uses of overridden methods.
1 parent 80ab069 commit 8c126f1

2 files changed

Lines changed: 75 additions & 3 deletions

File tree

Lib/test/test_decimal.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5398,6 +5398,34 @@ def test_sizeof(self):
53985398
y = Decimal(10**(9*25)).__sizeof__()
53995399
self.assertEqual(y, x+4)
54005400

5401+
def test_internal_use_of_overridden_methods(self):
5402+
Decimal = C.Decimal
5403+
5404+
# Unsound subtyping
5405+
class X(float):
5406+
def as_integer_ratio(self):
5407+
return 1
5408+
def __abs__(self):
5409+
return self
5410+
5411+
class Y(float):
5412+
def __abs__(self):
5413+
return [1]*200
5414+
5415+
class I(int):
5416+
def bit_length(self):
5417+
return [1]*200
5418+
5419+
class Z(float):
5420+
def as_integer_ratio(self):
5421+
return (I(1), I(1))
5422+
def __abs__(self):
5423+
return self
5424+
5425+
for cls in X, Y, Z:
5426+
self.assertEqual(Decimal.from_float(cls(101.1)),
5427+
Decimal.from_float(101.1))
5428+
54015429
@requires_docstrings
54025430
@unittest.skipUnless(C, "test requires C version")
54035431
class SignatureTest(unittest.TestCase):

Modules/_decimal/_decimal.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2208,6 +2208,14 @@ PyDecType_FromLongExact(PyTypeObject *type, const PyObject *pylong,
22082208
return dec;
22092209
}
22102210

2211+
/* External C-API functions */
2212+
static binaryfunc _py_long_multiply;
2213+
static binaryfunc _py_long_floor_divide;
2214+
static ternaryfunc _py_long_power;
2215+
static unaryfunc _py_float_abs;
2216+
static PyCFunction _py_long_bit_length;
2217+
static PyCFunction _py_float_as_integer_ratio;
2218+
22112219
/* Return a PyDecObject or a subtype from a PyFloatObject.
22122220
Conversion is exact. */
22132221
static PyObject *
@@ -2258,21 +2266,21 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v,
22582266
}
22592267

22602268
/* absolute value of the float */
2261-
tmp = PyObject_CallMethod(v, "__abs__", NULL);
2269+
tmp = _py_float_abs(v);
22622270
if (tmp == NULL) {
22632271
return NULL;
22642272
}
22652273

22662274
/* float as integer ratio: numerator/denominator */
2267-
n_d = PyObject_CallMethod(tmp, "as_integer_ratio", NULL);
2275+
n_d = _py_float_as_integer_ratio(tmp, NULL);
22682276
Py_DECREF(tmp);
22692277
if (n_d == NULL) {
22702278
return NULL;
22712279
}
22722280
n = PyTuple_GET_ITEM(n_d, 0);
22732281
d = PyTuple_GET_ITEM(n_d, 1);
22742282

2275-
tmp = PyObject_CallMethod(d, "bit_length", NULL);
2283+
tmp = _py_long_bit_length(d, NULL);
22762284
if (tmp == NULL) {
22772285
Py_DECREF(n_d);
22782286
return NULL;
@@ -5511,6 +5519,32 @@ static struct int_constmap int_constants [] = {
55115519
#define CHECK_PTR(expr) \
55125520
do { if ((expr) == NULL) goto error; } while (0)
55135521

5522+
5523+
static PyCFunction
5524+
cfunc_noargs(PyTypeObject *t, const char *name)
5525+
{
5526+
struct PyMethodDef *m;
5527+
5528+
if (t->tp_methods == NULL) {
5529+
goto error;
5530+
}
5531+
5532+
for (m = t->tp_methods; m->ml_name != NULL; m++) {
5533+
if (strcmp(name, m->ml_name) == 0) {
5534+
if (!(m->ml_flags & METH_NOARGS)) {
5535+
goto error;
5536+
}
5537+
return m->ml_meth;
5538+
}
5539+
}
5540+
5541+
error:
5542+
PyErr_Format(PyExc_RuntimeError,
5543+
"internal error: could not find method %s", name);
5544+
return NULL;
5545+
}
5546+
5547+
55145548
PyMODINIT_FUNC
55155549
PyInit__decimal(void)
55165550
{
@@ -5535,6 +5569,16 @@ PyInit__decimal(void)
55355569
mpd_setminalloc(_Py_DEC_MINALLOC);
55365570

55375571

5572+
/* Init external C-API functions */
5573+
_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply;
5574+
_py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide;
5575+
_py_long_power = PyLong_Type.tp_as_number->nb_power;
5576+
_py_float_abs = PyFloat_Type.tp_as_number->nb_absolute;
5577+
ASSIGN_PTR(_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type,
5578+
"as_integer_ratio"));
5579+
ASSIGN_PTR(_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length"));
5580+
5581+
55385582
/* Init types */
55395583
PyDec_Type.tp_base = &PyBaseObject_Type;
55405584
PyDecContext_Type.tp_base = &PyBaseObject_Type;

0 commit comments

Comments
 (0)