Skip to content

Commit f8a736b

Browse files
authored
gh-123446: Fix empty function names in TypeErrors in typeobject (#123470)
1 parent 32c7dbb commit f8a736b

File tree

3 files changed

+63
-11
lines changed

3 files changed

+63
-11
lines changed

Lib/test/test_descr.py

+14
Original file line numberDiff line numberDiff line change
@@ -4021,6 +4021,20 @@ def test_ipow_exception_text(self):
40214021
y = x ** 2
40224022
self.assertIn('unsupported operand type(s) for **', str(cm.exception))
40234023

4024+
def test_pow_wrapper_error_messages(self):
4025+
self.assertRaisesRegex(TypeError,
4026+
'expected 1 or 2 arguments, got 0',
4027+
int().__pow__)
4028+
self.assertRaisesRegex(TypeError,
4029+
'expected 1 or 2 arguments, got 3',
4030+
int().__pow__, 1, 2, 3)
4031+
self.assertRaisesRegex(TypeError,
4032+
'expected 1 or 2 arguments, got 0',
4033+
int().__rpow__)
4034+
self.assertRaisesRegex(TypeError,
4035+
'expected 1 or 2 arguments, got 3',
4036+
int().__rpow__, 1, 2, 3)
4037+
40244038
def test_mutable_bases(self):
40254039
# Testing mutable bases...
40264040

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix empty function name in :exc:`TypeError` when builtin magic methods are
2+
used without the required args.

Objects/typeobject.c

+47-11
Original file line numberDiff line numberDiff line change
@@ -8678,6 +8678,27 @@ check_num_args(PyObject *ob, int n)
86788678
return 0;
86798679
}
86808680

8681+
static Py_ssize_t
8682+
check_pow_args(PyObject *ob)
8683+
{
8684+
// Returns the argument count on success or `-1` on error.
8685+
int min = 1;
8686+
int max = 2;
8687+
if (!PyTuple_CheckExact(ob)) {
8688+
PyErr_SetString(PyExc_SystemError,
8689+
"PyArg_UnpackTuple() argument list is not a tuple");
8690+
return -1;
8691+
}
8692+
Py_ssize_t size = PyTuple_GET_SIZE(ob);
8693+
if (size >= min && size <= max) {
8694+
return size;
8695+
}
8696+
PyErr_Format(
8697+
PyExc_TypeError,
8698+
"expected %d or %d arguments, got %zd", min, max, PyTuple_GET_SIZE(ob));
8699+
return -1;
8700+
}
8701+
86818702
/* Generic wrappers for overloadable 'operators' such as __getitem__ */
86828703

86838704
/* There's a wrapper *function* for each distinct function typedef used
@@ -8759,8 +8780,15 @@ wrap_ternaryfunc(PyObject *self, PyObject *args, void *wrapped)
87598780

87608781
/* Note: This wrapper only works for __pow__() */
87618782

8762-
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
8783+
Py_ssize_t size = check_pow_args(args);
8784+
if (size == -1) {
87638785
return NULL;
8786+
}
8787+
other = PyTuple_GET_ITEM(args, 0);
8788+
if (size == 2) {
8789+
third = PyTuple_GET_ITEM(args, 1);
8790+
}
8791+
87648792
return (*func)(self, other, third);
87658793
}
87668794

@@ -8771,10 +8799,17 @@ wrap_ternaryfunc_r(PyObject *self, PyObject *args, void *wrapped)
87718799
PyObject *other;
87728800
PyObject *third = Py_None;
87738801

8774-
/* Note: This wrapper only works for __pow__() */
8802+
/* Note: This wrapper only works for __rpow__() */
87758803

8776-
if (!PyArg_UnpackTuple(args, "", 1, 2, &other, &third))
8804+
Py_ssize_t size = check_pow_args(args);
8805+
if (size == -1) {
87778806
return NULL;
8807+
}
8808+
other = PyTuple_GET_ITEM(args, 0);
8809+
if (size == 2) {
8810+
third = PyTuple_GET_ITEM(args, 1);
8811+
}
8812+
87788813
return (*func)(other, self, third);
87798814
}
87808815

@@ -8795,8 +8830,9 @@ wrap_indexargfunc(PyObject *self, PyObject *args, void *wrapped)
87958830
PyObject* o;
87968831
Py_ssize_t i;
87978832

8798-
if (!PyArg_UnpackTuple(args, "", 1, 1, &o))
8833+
if (!check_num_args(args, 1))
87998834
return NULL;
8835+
o = PyTuple_GET_ITEM(args, 0);
88008836
i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
88018837
if (i == -1 && PyErr_Occurred())
88028838
return NULL;
@@ -8852,7 +8888,7 @@ wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped)
88528888
int res;
88538889
PyObject *arg, *value;
88548890

8855-
if (!PyArg_UnpackTuple(args, "", 2, 2, &arg, &value))
8891+
if (!PyArg_UnpackTuple(args, "__setitem__", 2, 2, &arg, &value))
88568892
return NULL;
88578893
i = getindex(self, arg);
88588894
if (i == -1 && PyErr_Occurred())
@@ -8908,7 +8944,7 @@ wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped)
89088944
int res;
89098945
PyObject *key, *value;
89108946

8911-
if (!PyArg_UnpackTuple(args, "", 2, 2, &key, &value))
8947+
if (!PyArg_UnpackTuple(args, "__setitem__", 2, 2, &key, &value))
89128948
return NULL;
89138949
res = (*func)(self, key, value);
89148950
if (res == -1 && PyErr_Occurred())
@@ -9005,7 +9041,7 @@ wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
90059041
int res;
90069042
PyObject *name, *value;
90079043

9008-
if (!PyArg_UnpackTuple(args, "", 2, 2, &name, &value))
9044+
if (!PyArg_UnpackTuple(args, "__setattr__", 2, 2, &name, &value))
90099045
return NULL;
90109046
if (!hackcheck(self, func, "__setattr__"))
90119047
return NULL;
@@ -9115,7 +9151,7 @@ wrap_descr_get(PyObject *self, PyObject *args, void *wrapped)
91159151
PyObject *obj;
91169152
PyObject *type = NULL;
91179153

9118-
if (!PyArg_UnpackTuple(args, "", 1, 2, &obj, &type))
9154+
if (!PyArg_UnpackTuple(args, "__get__", 1, 2, &obj, &type))
91199155
return NULL;
91209156
if (obj == Py_None)
91219157
obj = NULL;
@@ -9136,7 +9172,7 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped)
91369172
PyObject *obj, *value;
91379173
int ret;
91389174

9139-
if (!PyArg_UnpackTuple(args, "", 2, 2, &obj, &value))
9175+
if (!PyArg_UnpackTuple(args, "__set__", 2, 2, &obj, &value))
91409176
return NULL;
91419177
ret = (*func)(self, obj, value);
91429178
if (ret < 0)
@@ -9165,7 +9201,7 @@ wrap_buffer(PyObject *self, PyObject *args, void *wrapped)
91659201
{
91669202
PyObject *arg = NULL;
91679203

9168-
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) {
9204+
if (!PyArg_UnpackTuple(args, "__buffer__", 1, 1, &arg)) {
91699205
return NULL;
91709206
}
91719207
Py_ssize_t flags = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
@@ -9186,7 +9222,7 @@ static PyObject *
91869222
wrap_releasebuffer(PyObject *self, PyObject *args, void *wrapped)
91879223
{
91889224
PyObject *arg = NULL;
9189-
if (!PyArg_UnpackTuple(args, "", 1, 1, &arg)) {
9225+
if (!PyArg_UnpackTuple(args, "__release_buffer__", 1, 1, &arg)) {
91909226
return NULL;
91919227
}
91929228
if (!PyMemoryView_Check(arg)) {

0 commit comments

Comments
 (0)