@@ -4006,26 +4006,30 @@ PyObject*
40064006_PyString_FormatLong (PyObject * val , int flags , int prec , int type ,
40074007 char * * pbuf , int * plen )
40084008{
4009- PyObject * result = NULL ;
4009+ PyObject * result = NULL , * r1 ;
4010+ const char * s ;
40104011 char * buf ;
40114012 Py_ssize_t i ;
40124013 int sign ; /* 1 if '-', else 0 */
40134014 int len ; /* number of characters */
40144015 Py_ssize_t llen ;
4015- int numdigits ; /* len == numnondigits + numdigits */
4016- int numnondigits = 0 ;
4016+ int numdigits ; /* len == numnondigits + skipped + numdigits */
4017+ int numnondigits , skipped , filled ;
4018+ const char * method ;
40174019
40184020 switch (type ) {
40194021 case 'd' :
40204022 case 'u' :
4023+ method = "str" ;
40214024 result = Py_TYPE (val )-> tp_str (val );
40224025 break ;
40234026 case 'o' :
4027+ method = "oct" ;
40244028 result = Py_TYPE (val )-> tp_as_number -> nb_oct (val );
40254029 break ;
40264030 case 'x' :
40274031 case 'X' :
4028- numnondigits = 2 ;
4032+ method = "hex" ;
40294033 result = Py_TYPE (val )-> tp_as_number -> nb_hex (val );
40304034 break ;
40314035 default :
@@ -4034,97 +4038,109 @@ _PyString_FormatLong(PyObject *val, int flags, int prec, int type,
40344038 if (!result )
40354039 return NULL ;
40364040
4037- buf = PyString_AsString (result );
4038- if (!buf ) {
4041+ if (PyString_AsStringAndSize (result , (char * * )& s , & llen ) < 0 ) {
40394042 Py_DECREF (result );
40404043 return NULL ;
40414044 }
4042-
4043- /* To modify the string in-place, there can only be one reference. */
4044- if (Py_REFCNT (result ) != 1 ) {
4045- PyErr_BadInternalCall ();
4046- return NULL ;
4047- }
4048- llen = PyString_Size (result );
40494045 if (llen > INT_MAX ) {
40504046 PyErr_SetString (PyExc_ValueError , "string too large in _PyString_FormatLong" );
4047+ Py_DECREF (result );
40514048 return NULL ;
40524049 }
40534050 len = (int )llen ;
4054- if (buf [len - 1 ] == 'L' ) {
4051+ if (len > 0 && s [len - 1 ] == 'L' ) {
40554052 -- len ;
4056- buf [len ] = '\0' ;
4057- }
4058- sign = buf [0 ] == '-' ;
4059- numnondigits += sign ;
4060- numdigits = len - numnondigits ;
4061- assert (numdigits > 0 );
4062-
4063- /* Get rid of base marker unless F_ALT */
4064- if ((flags & F_ALT ) == 0 ) {
4065- /* Need to skip 0x, 0X or 0. */
4066- int skipped = 0 ;
4067- switch (type ) {
4068- case 'o' :
4069- assert (buf [sign ] == '0' );
4070- /* If 0 is only digit, leave it alone. */
4071- if (numdigits > 1 ) {
4072- skipped = 1 ;
4073- -- numdigits ;
4074- }
4075- break ;
4076- case 'x' :
4077- case 'X' :
4078- assert (buf [sign ] == '0' );
4079- assert (buf [sign + 1 ] == 'x' );
4053+ if (len == 0 )
4054+ goto error ;
4055+ }
4056+ sign = s [0 ] == '-' ;
4057+ numnondigits = sign ;
4058+
4059+ /* Need to skip 0x, 0X or 0. */
4060+ skipped = 0 ;
4061+ switch (type ) {
4062+ case 'o' :
4063+ if (s [sign ] != '0' )
4064+ goto error ;
4065+ /* If 0 is only digit, leave it alone. */
4066+ if ((flags & F_ALT ) == 0 && len - sign > 1 )
4067+ skipped = 1 ;
4068+ break ;
4069+ case 'x' :
4070+ case 'X' :
4071+ if (s [sign ] != '0' || (s [sign + 1 ] != 'x' && s [sign + 1 ] != 'X' ))
4072+ goto error ;
4073+ if ((flags & F_ALT ) == 0 )
40804074 skipped = 2 ;
4081- numnondigits -= 2 ;
4082- break ;
4083- }
4084- if (skipped ) {
4085- buf += skipped ;
4086- len -= skipped ;
4087- if (sign )
4088- buf [0 ] = '-' ;
4089- }
4090- assert (len == numnondigits + numdigits );
4091- assert (numdigits > 0 );
4075+ else
4076+ numnondigits += 2 ;
4077+ break ;
40924078 }
4079+ numdigits = len - numnondigits - skipped ;
4080+ if (numdigits <= 0 )
4081+ goto error ;
4082+
4083+ filled = prec - numdigits ;
4084+ if (filled < 0 )
4085+ filled = 0 ;
4086+ len = numnondigits + filled + numdigits ;
40934087
4094- /* Fill with leading zeroes to meet minimum width. */
4095- if (prec > numdigits ) {
4096- PyObject * r1 = PyString_FromStringAndSize (NULL ,
4097- numnondigits + prec );
4098- char * b1 ;
4099- if (!r1 ) {
4100- Py_DECREF (result );
4088+ /* To modify the string in-place, there can only be one reference. */
4089+ if (skipped >= filled &&
4090+ PyString_CheckExact (result ) &&
4091+ Py_REFCNT (result ) == 1 &&
4092+ !PyString_CHECK_INTERNED (result ))
4093+ {
4094+ r1 = NULL ;
4095+ buf = (char * )s + skipped - filled ;
4096+ }
4097+ else {
4098+ r1 = result ;
4099+ result = PyString_FromStringAndSize (NULL , len );
4100+ if (!result ) {
4101+ Py_DECREF (r1 );
41014102 return NULL ;
41024103 }
4103- b1 = PyString_AS_STRING (r1 );
4104- for (i = 0 ; i < numnondigits ; ++ i )
4105- * b1 ++ = * buf ++ ;
4106- for (i = 0 ; i < prec - numdigits ; i ++ )
4107- * b1 ++ = '0' ;
4108- for (i = 0 ; i < numdigits ; i ++ )
4109- * b1 ++ = * buf ++ ;
4110- * b1 = '\0' ;
4111- Py_DECREF (result );
4112- result = r1 ;
41134104 buf = PyString_AS_STRING (result );
4114- len = numnondigits + prec ;
41154105 }
41164106
4107+ for (i = numnondigits ; -- i >= 0 ;)
4108+ buf [i ] = s [i ];
4109+ buf += numnondigits ;
4110+ s += numnondigits + skipped ;
4111+ for (i = 0 ; i < filled ; i ++ )
4112+ * buf ++ = '0' ;
4113+ if (r1 == NULL ) {
4114+ assert (buf == s );
4115+ buf += numdigits ;
4116+ }
4117+ else {
4118+ for (i = 0 ; i < numdigits ; i ++ )
4119+ * buf ++ = * s ++ ;
4120+ }
4121+ * buf = '\0' ;
4122+ buf -= len ;
4123+ Py_XDECREF (r1 );
4124+
41174125 /* Fix up case for hex conversions. */
41184126 if (type == 'X' ) {
41194127 /* Need to convert all lower case letters to upper case.
41204128 and need to convert 0x to 0X (and -0x to -0X). */
4121- for (i = 0 ; i < len ; i ++ )
4122- if (buf [i ] >= 'a' && buf [i ] <= 'x ' )
4129+ for (i = 0 ; i < len ; i ++ ) {
4130+ if (buf [i ] >= 'a' && buf [i ] <= 'z ' )
41234131 buf [i ] -= 'a' - 'A' ;
4132+ }
41244133 }
41254134 * pbuf = buf ;
41264135 * plen = len ;
41274136 return result ;
4137+
4138+ error :
4139+ PyErr_Format (PyExc_ValueError ,
4140+ "%%%c format: invalid result of __%s__ (type=%.200s)" ,
4141+ type , method , Py_TYPE (val )-> tp_name );
4142+ Py_DECREF (result );
4143+ return NULL ;
41284144}
41294145
41304146Py_LOCAL_INLINE (int )
0 commit comments