diff -r 2a34cef7681b Objects/bytearrayobject.c --- a/Objects/bytearrayobject.c Mon Jul 11 14:21:58 2016 -0400 +++ b/Objects/bytearrayobject.c Tue Jul 12 14:56:24 2016 +0800 @@ -882,62 +882,57 @@ return -1; } -/* Mostly copied from string_repr, but without the +/* Mostly copied from PyBytes_Repr, but without the "smart quote" functionality. */ static PyObject * bytearray_repr(PyByteArrayObject *self) { const char *quote_prefix = "bytearray(b"; const char *quote_postfix = ")"; - Py_ssize_t length = Py_SIZE(self); - /* 15 == strlen(quote_prefix) + 2 + strlen(quote_postfix) + 1 */ - size_t newsize; + Py_ssize_t i, length = Py_SIZE(self); + Py_ssize_t newsize, squotes, dquotes; + unsigned char quote, *s, *p; PyObject *v; - Py_ssize_t i; - char *bytes; - char c; - char *p; - int quote; - char *test, *start; - char *buffer; - if (length > (PY_SSIZE_T_MAX - 15) / 4) { - PyErr_SetString(PyExc_OverflowError, - "bytearray object is too large to make repr"); - return NULL; + squotes = dquotes = 0; + newsize = strlen(quote_prefix) + 2 + strlen(quote_postfix); /* 2 quotes */ + s = (unsigned char*)PyByteArray_AS_STRING(self); + for (i = 0; i < length; i++) { + Py_ssize_t incr = 1; + switch(s[i]) { + case '\'': squotes++; break; + case '"': dquotes++; break; + case '\\': case '\t': case '\n': case '\r': + incr = 2; break; + default: + if (s[i] < ' ' || s[i] >= 0x7f) + incr = 4; + } + if (newsize > PY_SSIZE_T_MAX - incr) + goto overflow; + newsize += incr; + } + /* Figure out which quote to use; single is preferred */ + quote = '\''; + if (dquotes == 0 && squotes > 0) + quote = '"'; + if (squotes && quote == '\'') { + if (newsize > PY_SSIZE_T_MAX - squotes) + goto overflow; + newsize += squotes; } - newsize = 15 + length * 4; - buffer = PyObject_Malloc(newsize); - if (buffer == NULL) { - PyErr_NoMemory(); + v = PyUnicode_New(newsize, 127); + if (v == NULL) return NULL; - } + p = PyUnicode_1BYTE_DATA(v); - /* Figure out which quote to use; single is preferred */ - quote = '\''; - start = PyByteArray_AS_STRING(self); - for (test = start; test < start+length; ++test) { - if (*test == '"') { - quote = '\''; /* back to single */ - break; - } - else if (*test == '\'') - quote = '"'; - } - - p = buffer; while (*quote_prefix) *p++ = *quote_prefix++; *p++ = quote; - - bytes = PyByteArray_AS_STRING(self); for (i = 0; i < length; i++) { - /* There's at least enough room for a hex escape - and a closing quote. */ - assert(newsize - (p - buffer) >= 5); - c = bytes[i]; - if (c == '\'' || c == '\\') + unsigned char c = ((unsigned char *)PyByteArray_AS_STRING(self))[i]; + if (c == quote || c == '\\') *p++ = '\\', *p++ = c; else if (c == '\t') *p++ = '\\', *p++ = 't'; @@ -945,8 +940,6 @@ *p++ = '\\', *p++ = 'n'; else if (c == '\r') *p++ = '\\', *p++ = 'r'; - else if (c == 0) - *p++ = '\\', *p++ = 'x', *p++ = '0', *p++ = '0'; else if (c < ' ' || c >= 0x7f) { *p++ = '\\'; *p++ = 'x'; @@ -956,15 +949,16 @@ else *p++ = c; } - assert(newsize - (p - buffer) >= 1); *p++ = quote; - while (*quote_postfix) { - *p++ = *quote_postfix++; - } + while (*quote_postfix) + *p++ = *quote_postfix++; + assert(_PyUnicode_CheckConsistency(v, 1)); + return v; - v = PyUnicode_DecodeASCII(buffer, p - buffer, NULL); - PyObject_Free(buffer); - return v; + overflow: + PyErr_SetString(PyExc_OverflowError, + "bytearray object is too large to make repr"); + return NULL; } static PyObject *