Skip to content

Commit a36d270

Browse files
committed
gh-135763: Argument Clinic: Impl allow_negative for ssize_t
1 parent 95d6e0b commit a36d270

File tree

19 files changed

+195
-107
lines changed

19 files changed

+195
-107
lines changed

Include/internal/pycore_abstract.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ extern int _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls);
5151
// Export for '_bisect' shared extension.
5252
PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *);
5353

54+
// Convert Python int to Py_ssize_t. Do nothing if the argument is None.
55+
// Raises ValueError if argument is negative
56+
PyAPI_FUNC(int) _Py_convert_optional_to_non_negative_ssize_t(PyObject *, void *);
57+
5458
// Same as PyNumber_Index() but can return an instance of a subclass of int.
5559
// Export for 'math' shared extension.
5660
PyAPI_FUNC(PyObject*) _PyNumber_Index(PyObject *o);

Lib/test/clinic.test.c

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,12 +1612,14 @@ test_Py_ssize_t_converter
16121612
a: Py_ssize_t = 12
16131613
b: Py_ssize_t(accept={int}) = 34
16141614
c: Py_ssize_t(accept={int, NoneType}) = 56
1615+
d: Py_ssize_t(accept={int}, allow_negative=False) = 78
1616+
e: Py_ssize_t(accept={int, NoneType}, allow_negative=False) = 90
16151617
/
16161618
16171619
[clinic start generated code]*/
16181620

16191621
PyDoc_STRVAR(test_Py_ssize_t_converter__doc__,
1620-
"test_Py_ssize_t_converter($module, a=12, b=34, c=56, /)\n"
1622+
"test_Py_ssize_t_converter($module, a=12, b=34, c=56, d=78, e=90, /)\n"
16211623
"--\n"
16221624
"\n");
16231625

@@ -1626,7 +1628,7 @@ PyDoc_STRVAR(test_Py_ssize_t_converter__doc__,
16261628

16271629
static PyObject *
16281630
test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b,
1629-
Py_ssize_t c);
1631+
Py_ssize_t c, Py_ssize_t d, Py_ssize_t e);
16301632

16311633
static PyObject *
16321634
test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
@@ -1635,8 +1637,10 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
16351637
Py_ssize_t a = 12;
16361638
Py_ssize_t b = 34;
16371639
Py_ssize_t c = 56;
1640+
Py_ssize_t d = 78;
1641+
Py_ssize_t e = 90;
16381642

1639-
if (!_PyArg_CheckPositional("test_Py_ssize_t_converter", nargs, 0, 3)) {
1643+
if (!_PyArg_CheckPositional("test_Py_ssize_t_converter", nargs, 0, 5)) {
16401644
goto exit;
16411645
}
16421646
if (nargs < 1) {
@@ -1675,17 +1679,43 @@ test_Py_ssize_t_converter(PyObject *module, PyObject *const *args, Py_ssize_t na
16751679
if (!_Py_convert_optional_to_ssize_t(args[2], &c)) {
16761680
goto exit;
16771681
}
1682+
if (nargs < 4) {
1683+
goto skip_optional;
1684+
}
1685+
{
1686+
Py_ssize_t ival = -1;
1687+
PyObject *iobj = _PyNumber_Index(args[3]);
1688+
if (iobj != NULL) {
1689+
ival = PyLong_AsSsize_t(iobj);
1690+
Py_DECREF(iobj);
1691+
}
1692+
if (ival == -1 && PyErr_Occurred()) {
1693+
goto exit;
1694+
}
1695+
d = ival;
1696+
if (d < 0) {
1697+
PyErr_SetString(PyExc_ValueError,
1698+
"d must not be negative");
1699+
goto exit;
1700+
}
1701+
}
1702+
if (nargs < 5) {
1703+
goto skip_optional;
1704+
}
1705+
if (!_Py_convert_optional_to_non_negative_ssize_t(args[4], &e)) {
1706+
goto exit;
1707+
}
16781708
skip_optional:
1679-
return_value = test_Py_ssize_t_converter_impl(module, a, b, c);
1709+
return_value = test_Py_ssize_t_converter_impl(module, a, b, c, d, e);
16801710

16811711
exit:
16821712
return return_value;
16831713
}
16841714

16851715
static PyObject *
16861716
test_Py_ssize_t_converter_impl(PyObject *module, Py_ssize_t a, Py_ssize_t b,
1687-
Py_ssize_t c)
1688-
/*[clinic end generated code: output=48214bc3d01f4dd7 input=3855f184bb3f299d]*/
1717+
Py_ssize_t c, Py_ssize_t d, Py_ssize_t e)
1718+
/*[clinic end generated code: output=df3873c05e53e497 input=5c693ea198fa3dd5]*/
16891719

16901720

16911721
/*[clinic input]
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add ``allow_negative`` flag to ``Py_ssize_t`` Argument Clinic converter, to
2+
enable generation of bound checking

Modules/_ctypes/_ctypes.c

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ _ctypes.CDataType.from_buffer as CDataType_from_buffer
859859
type: self
860860
cls: defining_class
861861
obj: object
862-
offset: Py_ssize_t = 0
862+
offset: Py_ssize_t(allow_negative=False) = 0
863863
/
864864
865865
C.from_buffer(object, offset=0) -> C instance
@@ -870,7 +870,7 @@ Create a C instance from a writeable buffer.
870870
static PyObject *
871871
CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj,
872872
Py_ssize_t offset)
873-
/*[clinic end generated code: output=57604e99635abd31 input=0f36cedd105ca28d]*/
873+
/*[clinic end generated code: output=57604e99635abd31 input=8f43e6bc44373180]*/
874874
{
875875
PyObject *mv;
876876
PyObject *result;
@@ -906,13 +906,6 @@ CDataType_from_buffer_impl(PyObject *type, PyTypeObject *cls, PyObject *obj,
906906
return NULL;
907907
}
908908

909-
if (offset < 0) {
910-
PyErr_SetString(PyExc_ValueError,
911-
"offset cannot be negative");
912-
Py_DECREF(mv);
913-
return NULL;
914-
}
915-
916909
if (info->size > buffer->len - offset) {
917910
PyErr_Format(PyExc_ValueError,
918911
"Buffer size too small "
@@ -955,7 +948,7 @@ _ctypes.CDataType.from_buffer_copy as CDataType_from_buffer_copy
955948
type: self
956949
cls: defining_class
957950
buffer: Py_buffer
958-
offset: Py_ssize_t = 0
951+
offset: Py_ssize_t(allow_negative=False) = 0
959952
/
960953
961954
C.from_buffer_copy(object, offset=0) -> C instance
@@ -966,7 +959,7 @@ Create a C instance from a readable buffer.
966959
static PyObject *
967960
CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls,
968961
Py_buffer *buffer, Py_ssize_t offset)
969-
/*[clinic end generated code: output=c8fc62b03e5cc6fa input=2a81e11b765a6253]*/
962+
/*[clinic end generated code: output=c8fc62b03e5cc6fa input=41f97f512295ceec]*/
970963
{
971964
PyObject *result;
972965

@@ -980,12 +973,6 @@ CDataType_from_buffer_copy_impl(PyObject *type, PyTypeObject *cls,
980973
return NULL;
981974
}
982975

983-
if (offset < 0) {
984-
PyErr_SetString(PyExc_ValueError,
985-
"offset cannot be negative");
986-
return NULL;
987-
}
988-
989976
if (info->size > buffer->len - offset) {
990977
PyErr_Format(PyExc_ValueError,
991978
"Buffer size too small (%zd instead of at least %zd bytes)",

Modules/_ctypes/callproc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1874,14 +1874,14 @@ My_Py_DECREF(PyObject *self, PyObject *arg)
18741874
@critical_section obj
18751875
_ctypes.resize
18761876
obj: object(subclass_of="clinic_state()->PyCData_Type", type="CDataObject *")
1877-
size: Py_ssize_t
1877+
size: Py_ssize_t(allow_negative=False)
18781878
/
18791879
18801880
[clinic start generated code]*/
18811881

18821882
static PyObject *
18831883
_ctypes_resize_impl(PyObject *module, CDataObject *obj, Py_ssize_t size)
1884-
/*[clinic end generated code: output=11c89c7dbdbcd53f input=bf5a6aaea8514261]*/
1884+
/*[clinic end generated code: output=11c89c7dbdbcd53f input=1c986b76598bf0eb]*/
18851885
{
18861886
ctypes_state *st = get_module_state(module);
18871887
StgInfo *info;

Modules/_ctypes/clinic/_ctypes.c.h

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_ctypes/clinic/callproc.c.h

Lines changed: 6 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_hashopenssl.c

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,23 +1017,18 @@ static PyType_Spec HASHobject_type_spec = {
10171017
/*[clinic input]
10181018
_hashlib.HASHXOF.digest
10191019
1020-
length: Py_ssize_t
1020+
length: Py_ssize_t(allow_negative=False)
10211021
10221022
Return the digest value as a bytes object.
10231023
[clinic start generated code]*/
10241024

10251025
static PyObject *
10261026
_hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length)
1027-
/*[clinic end generated code: output=dcb09335dd2fe908 input=3eb034ce03c55b21]*/
1027+
/*[clinic end generated code: output=dcb09335dd2fe908 input=224d047da2c12a42]*/
10281028
{
10291029
EVP_MD_CTX *temp_ctx;
10301030
PyObject *retval;
10311031

1032-
if (length < 0) {
1033-
PyErr_SetString(PyExc_ValueError, "negative digest length");
1034-
return NULL;
1035-
}
1036-
10371032
if (length == 0) {
10381033
return Py_GetConstant(Py_CONSTANT_EMPTY_BYTES);
10391034
}
@@ -1072,24 +1067,19 @@ _hashlib_HASHXOF_digest_impl(HASHobject *self, Py_ssize_t length)
10721067
/*[clinic input]
10731068
_hashlib.HASHXOF.hexdigest
10741069
1075-
length: Py_ssize_t
1070+
length: Py_ssize_t(allow_negative=False)
10761071
10771072
Return the digest value as a string of hexadecimal digits.
10781073
[clinic start generated code]*/
10791074

10801075
static PyObject *
10811076
_hashlib_HASHXOF_hexdigest_impl(HASHobject *self, Py_ssize_t length)
1082-
/*[clinic end generated code: output=519431cafa014f39 input=0e58f7238adb7ab8]*/
1077+
/*[clinic end generated code: output=519431cafa014f39 input=4a41b8ab5d3bfee2]*/
10831078
{
10841079
unsigned char *digest;
10851080
EVP_MD_CTX *temp_ctx;
10861081
PyObject *retval;
10871082

1088-
if (length < 0) {
1089-
PyErr_SetString(PyExc_ValueError, "negative digest length");
1090-
return NULL;
1091-
}
1092-
10931083
if (length == 0) {
10941084
return Py_GetConstant(Py_CONSTANT_EMPTY_STR);
10951085
}

Modules/arraymodule.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,7 +1526,7 @@ array.array.fromfile
15261526
15271527
cls: defining_class
15281528
f: object
1529-
n: Py_ssize_t
1529+
n: Py_ssize_t(allow_negative=False)
15301530
/
15311531
15321532
Read n objects from the file object f and append them to the end of the array.
@@ -1535,17 +1535,13 @@ Read n objects from the file object f and append them to the end of the array.
15351535
static PyObject *
15361536
array_array_fromfile_impl(arrayobject *self, PyTypeObject *cls, PyObject *f,
15371537
Py_ssize_t n)
1538-
/*[clinic end generated code: output=83a667080b345ebc input=b2b4bdfb7ad4d4ae]*/
1538+
/*[clinic end generated code: output=83a667080b345ebc input=db46b06ac1b6de87]*/
15391539
{
15401540
PyObject *b, *res;
15411541
Py_ssize_t itemsize = self->ob_descr->itemsize;
15421542
Py_ssize_t nbytes;
15431543
int not_enough_bytes;
15441544

1545-
if (n < 0) {
1546-
PyErr_SetString(PyExc_ValueError, "negative count");
1547-
return NULL;
1548-
}
15491545
if (n > PY_SSIZE_T_MAX / itemsize) {
15501546
PyErr_NoMemory();
15511547
return NULL;

Modules/clinic/_hashopenssl.c.h

Lines changed: 11 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)