@@ -420,21 +420,38 @@ class Py_ssize_t_converter(CConverter):
420420 type = 'Py_ssize_t'
421421 c_ignored_default = "0"
422422
423- def converter_init (self , * , accept : TypeSet = {int }) -> None :
423+ def converter_init (self , * , accept : TypeSet = {int }, allow_negative : bool = True ) -> None :
424+ self .allow_negative = allow_negative
424425 if accept == {int }:
425426 self .format_unit = 'n'
426427 self .default_type = int
427428 elif accept == {int , NoneType }:
428- self .converter = '_Py_convert_optional_to_ssize_t'
429+ if self .allow_negative :
430+ self .converter = '_Py_convert_optional_to_ssize_t'
431+ else :
432+ self .converter = '_Py_convert_optional_to_non_negative_ssize_t'
429433 else :
430434 fail (f"Py_ssize_t_converter: illegal 'accept' argument { accept !r} " )
431435
432436 def use_converter (self ) -> None :
433437 if self .converter == '_Py_convert_optional_to_ssize_t' :
434438 self .add_include ('pycore_abstract.h' ,
435439 '_Py_convert_optional_to_ssize_t()' )
440+ elif self .converter == '_Py_convert_optional_to_non_negative_ssize_t' :
441+ self .add_include ('pycore_abstract.h' ,
442+ '_Py_convert_optional_to_non_negative_ssize_t()' )
436443
437444 def parse_arg (self , argname : str , displayname : str , * , limited_capi : bool ) -> str | None :
445+ if self .allow_negative :
446+ non_negative_check = ""
447+ else :
448+ non_negative_check = self .format_code ("""
449+ if ({paramname} < 0) {{{{
450+ PyErr_SetString(PyExc_ValueError,
451+ "{paramname} must not be negative");
452+ goto exit;
453+ }}}}""" ,
454+ argname = argname )
438455 if self .format_unit == 'n' :
439456 if limited_capi :
440457 PyNumber_Index = 'PyNumber_Index'
@@ -452,11 +469,12 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st
452469 if (ival == -1 && PyErr_Occurred()) {{{{
453470 goto exit;
454471 }}}}
455- {paramname} = ival;
472+ {paramname} = ival;{non_negative_check}
456473 }}}}
457474 """ ,
458475 argname = argname ,
459- PyNumber_Index = PyNumber_Index )
476+ PyNumber_Index = PyNumber_Index ,
477+ non_negative_check = non_negative_check )
460478 if not limited_capi :
461479 return super ().parse_arg (argname , displayname , limited_capi = limited_capi )
462480 return self .format_code ("""
@@ -465,7 +483,7 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st
465483 {paramname} = PyNumber_AsSsize_t({argname}, PyExc_OverflowError);
466484 if ({paramname} == -1 && PyErr_Occurred()) {{{{
467485 goto exit;
468- }}}}
486+ }}}}{non_negative_check}
469487 }}}}
470488 else {{{{
471489 {bad_argument}
@@ -475,6 +493,7 @@ def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> st
475493 """ ,
476494 argname = argname ,
477495 bad_argument = self .bad_argument (displayname , 'integer or None' , limited_capi = limited_capi ),
496+ non_negative_check = non_negative_check
478497 )
479498
480499
0 commit comments