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

Skip to content

Commit 3d5881e

Browse files
committed
Issue #12909: Make PyLong_As* functions consistent in their use of exceptions.
PyLong_AsDouble() and PyLong_AsUnsignedLongLong() now raise TypeError (rather than SystemError) when passed a non-integer argument, matching the behavior of all the other PyLong_As*() functions.
1 parent 425fcd3 commit 3d5881e

3 files changed

Lines changed: 100 additions & 2 deletions

File tree

Modules/_testcapimodule.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,68 @@ test_long_long_and_overflow(PyObject *self)
769769
return Py_None;
770770
}
771771

772+
/* Test the PyLong_As{Size,Ssize}_t API. At present this just tests that
773+
non-integer arguments are handled correctly. It should be extended to
774+
test overflow handling.
775+
*/
776+
777+
static PyObject *
778+
test_long_as_size_t(PyObject *self)
779+
{
780+
size_t out_u;
781+
Py_ssize_t out_s;
782+
783+
Py_INCREF(Py_None);
784+
785+
out_u = PyLong_AsSize_t(Py_None);
786+
if (out_u != (size_t)-1 || !PyErr_Occurred())
787+
return raiseTestError("test_long_as_size_t",
788+
"PyLong_AsSize_t(None) didn't complain");
789+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
790+
return raiseTestError("test_long_as_size_t",
791+
"PyLong_AsSize_t(None) raised "
792+
"something other than TypeError");
793+
PyErr_Clear();
794+
795+
out_s = PyLong_AsSsize_t(Py_None);
796+
if (out_s != (Py_ssize_t)-1 || !PyErr_Occurred())
797+
return raiseTestError("test_long_as_size_t",
798+
"PyLong_AsSsize_t(None) didn't complain");
799+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
800+
return raiseTestError("test_long_as_size_t",
801+
"PyLong_AsSsize_t(None) raised "
802+
"something other than TypeError");
803+
PyErr_Clear();
804+
805+
/* Py_INCREF(Py_None) omitted - we already have a reference to it. */
806+
return Py_None;
807+
}
808+
809+
/* Test the PyLong_AsDouble API. At present this just tests that
810+
non-integer arguments are handled correctly.
811+
*/
812+
813+
static PyObject *
814+
test_long_as_double(PyObject *self)
815+
{
816+
double out;
817+
818+
Py_INCREF(Py_None);
819+
820+
out = PyLong_AsDouble(Py_None);
821+
if (out != -1.0 || !PyErr_Occurred())
822+
return raiseTestError("test_long_as_double",
823+
"PyLong_AsDouble(None) didn't complain");
824+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
825+
return raiseTestError("test_long_as_double",
826+
"PyLong_AsDouble(None) raised "
827+
"something other than TypeError");
828+
PyErr_Clear();
829+
830+
/* Py_INCREF(Py_None) omitted - we already have a reference to it. */
831+
return Py_None;
832+
}
833+
772834
/* Test the L code for PyArg_ParseTuple. This should deliver a PY_LONG_LONG
773835
for both long and int arguments. The test may leak a little memory if
774836
it fails.
@@ -2267,6 +2329,8 @@ static PyMethodDef TestMethods[] = {
22672329
{"test_long_api", (PyCFunction)test_long_api, METH_NOARGS},
22682330
{"test_long_and_overflow", (PyCFunction)test_long_and_overflow,
22692331
METH_NOARGS},
2332+
{"test_long_as_double", (PyCFunction)test_long_as_double,METH_NOARGS},
2333+
{"test_long_as_size_t", (PyCFunction)test_long_as_size_t,METH_NOARGS},
22702334
{"test_long_numbits", (PyCFunction)test_long_numbits, METH_NOARGS},
22712335
{"test_k_code", (PyCFunction)test_k_code, METH_NOARGS},
22722336
{"test_empty_argparse", (PyCFunction)test_empty_argparse,METH_NOARGS},

Modules/testcapi_long.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,32 @@ TESTNAME(PyObject *error(const char*))
177177
Py_DECREF(one);
178178
}
179179

180+
/* Test F_PY_TO_{S,U} on non-pylong input. This should raise a TypeError. */
181+
{
182+
TYPENAME out;
183+
unsigned TYPENAME uout;
184+
185+
Py_INCREF(Py_None);
186+
187+
out = F_PY_TO_S(Py_None);
188+
if (out != (TYPENAME)-1 || !PyErr_Occurred())
189+
return error("PyLong_AsXXX(None) didn't complain");
190+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
191+
return error("PyLong_AsXXX(None) raised "
192+
"something other than TypeError");
193+
PyErr_Clear();
194+
195+
uout = F_PY_TO_U(Py_None);
196+
if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
197+
return error("PyLong_AsXXX(None) didn't complain");
198+
if (!PyErr_ExceptionMatches(PyExc_TypeError))
199+
return error("PyLong_AsXXX(None) raised "
200+
"something other than TypeError");
201+
PyErr_Clear();
202+
203+
Py_DECREF(Py_None);
204+
}
205+
180206
Py_INCREF(Py_None);
181207
return Py_None;
182208
}

Objects/longobject.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,10 +1193,14 @@ PyLong_AsUnsignedLongLong(PyObject *vv)
11931193
int one = 1;
11941194
int res;
11951195

1196-
if (vv == NULL || !PyLong_Check(vv)) {
1196+
if (vv == NULL) {
11971197
PyErr_BadInternalCall();
11981198
return (unsigned PY_LONG_LONG)-1;
11991199
}
1200+
if (!PyLong_Check(vv)) {
1201+
PyErr_SetString(PyExc_TypeError, "an integer is required");
1202+
return (unsigned PY_LONG_LONG)-1;
1203+
}
12001204

12011205
v = (PyLongObject*)vv;
12021206
switch(Py_SIZE(v)) {
@@ -2481,10 +2485,14 @@ PyLong_AsDouble(PyObject *v)
24812485
Py_ssize_t exponent;
24822486
double x;
24832487

2484-
if (v == NULL || !PyLong_Check(v)) {
2488+
if (v == NULL) {
24852489
PyErr_BadInternalCall();
24862490
return -1.0;
24872491
}
2492+
if (!PyLong_Check(v)) {
2493+
PyErr_SetString(PyExc_TypeError, "an integer is required");
2494+
return -1.0;
2495+
}
24882496
x = _PyLong_Frexp((PyLongObject *)v, &exponent);
24892497
if ((x == -1.0 && PyErr_Occurred()) || exponent > DBL_MAX_EXP) {
24902498
PyErr_SetString(PyExc_OverflowError,

0 commit comments

Comments
 (0)