1 === modified file 'cjson.c'
2 --- a/cjson.c 2007-08-24 16:12:17 +0000
3 +++ b/cjson.c 2010-05-26 05:05:55 +0000
7 static const char *hexdigit = "0123456789abcdef";
8 +#ifdef Py_UNICODE_WIDE
9 + const Py_ssize_t expandsize = 10;
11 + const Py_ssize_t expandsize = 6;
14 + /* Initial allocation is based on the longest-possible unichr
17 + In wide (UTF-32) builds '\U00xxxxxx' is 10 chars per source
18 + unichr, so in this case it's the longest unichr escape. In
19 + narrow (UTF-16) builds this is five chars per source unichr
20 + since there are two unichrs in the surrogate pair, so in narrow
21 + (UTF-16) builds it's not the longest unichr escape.
23 + In wide or narrow builds '\uxxxx' is 6 chars per source unichr,
24 + so in the narrow (UTF-16) build case it's the longest unichr
28 s = PyUnicode_AS_UNICODE(unicode);
29 size = PyUnicode_GET_SIZE(unicode);
34 - repr = PyString_FromStringAndSize(NULL, 2 + 6*size + 1);
35 + repr = PyString_FromStringAndSize(NULL, 2 + expandsize*size + 1);
40 #ifdef Py_UNICODE_WIDE
41 /* Map 21-bit characters to '\U00xxxxxx' */
42 else if (ch >= 0x10000) {
43 - int offset = p - PyString_AS_STRING(repr);
45 - /* Resize the string if necessary */
46 - if (offset + 12 > PyString_GET_SIZE(repr)) {
47 - if (_PyString_Resize(&repr, PyString_GET_SIZE(repr) + 100))
49 - p = PyString_AS_STRING(repr) + offset;
54 *p++ = hexdigit[(ch >> 28) & 0x0000000F];
56 === modified file 'jsontest.py'
57 --- a/jsontest.py 2007-08-24 16:12:17 +0000
58 +++ b/jsontest.py 2010-05-26 05:05:55 +0000
61 def testWriteLong(self):
62 self.assertEqual("12345678901234567890", cjson.encode(12345678901234567890))
64 + def testWriteLongUnicode(self):
65 + # This test causes a buffer overrun in cjson 1.0.5, on UCS4 builds.
66 + # The string length is only resized for wide unicode characters if
67 + # there is less than 12 bytes of space left. Padding with
68 + # narrow-but-escaped characters prevents string resizing.
69 + # Note that u'\U0001D11E\u1234' also breaks, but sometimes goes
71 + s = cjson.encode(u'\U0001D11E\U0001D11E\U0001D11E\U0001D11E'
72 + u'\u1234\u1234\u1234\u1234\u1234\u1234')
73 + self.assertEqual(r'"\U0001d11e\U0001d11e\U0001d11e\U0001d11e'
74 + r'\u1234\u1234\u1234\u1234\u1234\u1234"', s)