From: Mark Dickinson Date: Tue, 20 Jan 2009 21:20:01 +0000 (+0000) Subject: Merged revisions 68814-68815 via svnmerge from X-Git-Tag: v3.0.1~112 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=053ce7e51d34f2f394a36d5d144c6ba9fc0bba0b;p=thirdparty%2FPython%2Fcpython.git Merged revisions 68814-68815 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ........ r68814 | mark.dickinson | 2009-01-20 20:43:58 +0000 (Tue, 20 Jan 2009) | 5 lines Issue #4842, patch 1/2: fix pickle in Python 3.x so that pickling with the 'L' opcode always appends an 'L' on output, just as 2.x does. When unpickling, remove the trailing 'L' (if present) before passing the result to PyLong_FromString. ........ r68815 | mark.dickinson | 2009-01-20 20:45:53 +0000 (Tue, 20 Jan 2009) | 2 lines Issue 4842, patch 2/2: int('3L') should be invalid in Python 3.x. ........ --- diff --git a/Lib/pickle.py b/Lib/pickle.py index 201dc9914bc7..c51d225eeeb4 100644 --- a/Lib/pickle.py +++ b/Lib/pickle.py @@ -470,7 +470,7 @@ class _Pickler: else: self.write(LONG4 + pack(">> dis(pickle.dumps(x, 1)) diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py index f65093ae41f6..4cebcd7bbc9f 100644 --- a/Lib/test/pickletester.py +++ b/Lib/test/pickletester.py @@ -90,21 +90,21 @@ class use_metaclass(object, metaclass=metaclass): # the object returned by create_data(). DATA0 = ( - b'(lp0\nL0\naL1\naF2.0\nac' + b'(lp0\nL0L\naL1L\naF2.0\nac' b'builtins\ncomplex\n' b'p1\n(F3.0\nF0.0\ntp2\nRp' - b'3\naL1\naL-1\naL255\naL-' - b'255\naL-256\naL65535\na' - b'L-65535\naL-65536\naL2' - b'147483647\naL-2147483' - b'647\naL-2147483648\na(' + b'3\naL1L\naL-1L\naL255L\naL-' + b'255L\naL-256L\naL65535L\na' + b'L-65535L\naL-65536L\naL2' + b'147483647L\naL-2147483' + b'647L\naL-2147483648L\na(' b'Vabc\np4\ng4\nccopyreg' b'\n_reconstructor\np5\n(' b'c__main__\nC\np6\ncbu' b'iltins\nobject\np7\nNt' b'p8\nRp9\n(dp10\nVfoo\np1' - b'1\nL1\nsVbar\np12\nL2\nsb' - b'g9\ntp13\nag13\naL5\na.' + b'1\nL1L\nsVbar\np12\nL2L\nsb' + b'g9\ntp13\nag13\naL5L\na.' ) # Disassembly of DATA0 @@ -113,80 +113,80 @@ DATA0_DIS = """\ 1: l LIST (MARK at 0) 2: p PUT 0 5: L LONG 0 - 8: a APPEND - 9: L LONG 1 - 12: a APPEND - 13: F FLOAT 2.0 - 18: a APPEND - 19: c GLOBAL 'builtins complex' - 37: p PUT 1 - 40: ( MARK - 41: F FLOAT 3.0 - 46: F FLOAT 0.0 - 51: t TUPLE (MARK at 40) - 52: p PUT 2 - 55: R REDUCE - 56: p PUT 3 - 59: a APPEND - 60: L LONG 1 - 63: a APPEND - 64: L LONG -1 - 68: a APPEND - 69: L LONG 255 - 74: a APPEND - 75: L LONG -255 - 81: a APPEND - 82: L LONG -256 - 88: a APPEND - 89: L LONG 65535 - 96: a APPEND - 97: L LONG -65535 - 105: a APPEND - 106: L LONG -65536 + 9: a APPEND + 10: L LONG 1 + 14: a APPEND + 15: F FLOAT 2.0 + 20: a APPEND + 21: c GLOBAL 'builtins complex' + 39: p PUT 1 + 42: ( MARK + 43: F FLOAT 3.0 + 48: F FLOAT 0.0 + 53: t TUPLE (MARK at 42) + 54: p PUT 2 + 57: R REDUCE + 58: p PUT 3 + 61: a APPEND + 62: L LONG 1 + 66: a APPEND + 67: L LONG -1 + 72: a APPEND + 73: L LONG 255 + 79: a APPEND + 80: L LONG -255 + 87: a APPEND + 88: L LONG -256 + 95: a APPEND + 96: L LONG 65535 + 104: a APPEND + 105: L LONG -65535 114: a APPEND - 115: L LONG 2147483647 - 127: a APPEND - 128: L LONG -2147483647 - 141: a APPEND - 142: L LONG -2147483648 - 155: a APPEND - 156: ( MARK - 157: V UNICODE 'abc' - 162: p PUT 4 - 165: g GET 4 - 168: c GLOBAL 'copyreg _reconstructor' - 192: p PUT 5 - 195: ( MARK - 196: c GLOBAL '__main__ C' - 208: p PUT 6 - 211: c GLOBAL 'builtins object' - 228: p PUT 7 - 231: N NONE - 232: t TUPLE (MARK at 195) - 233: p PUT 8 - 236: R REDUCE - 237: p PUT 9 - 240: ( MARK - 241: d DICT (MARK at 240) - 242: p PUT 10 - 246: V UNICODE 'foo' - 251: p PUT 11 - 255: L LONG 1 - 258: s SETITEM - 259: V UNICODE 'bar' - 264: p PUT 12 - 268: L LONG 2 - 271: s SETITEM - 272: b BUILD - 273: g GET 9 - 276: t TUPLE (MARK at 156) - 277: p PUT 13 - 281: a APPEND - 282: g GET 13 - 286: a APPEND - 287: L LONG 5 - 290: a APPEND - 291: . STOP + 115: L LONG -65536 + 124: a APPEND + 125: L LONG 2147483647 + 138: a APPEND + 139: L LONG -2147483647 + 153: a APPEND + 154: L LONG -2147483648 + 168: a APPEND + 169: ( MARK + 170: V UNICODE 'abc' + 175: p PUT 4 + 178: g GET 4 + 181: c GLOBAL 'copyreg _reconstructor' + 205: p PUT 5 + 208: ( MARK + 209: c GLOBAL '__main__ C' + 221: p PUT 6 + 224: c GLOBAL 'builtins object' + 241: p PUT 7 + 244: N NONE + 245: t TUPLE (MARK at 208) + 246: p PUT 8 + 249: R REDUCE + 250: p PUT 9 + 253: ( MARK + 254: d DICT (MARK at 253) + 255: p PUT 10 + 259: V UNICODE 'foo' + 264: p PUT 11 + 268: L LONG 1 + 272: s SETITEM + 273: V UNICODE 'bar' + 278: p PUT 12 + 282: L LONG 2 + 286: s SETITEM + 287: b BUILD + 288: g GET 9 + 291: t TUPLE (MARK at 169) + 292: p PUT 13 + 296: a APPEND + 297: g GET 13 + 301: a APPEND + 302: L LONG 5 + 306: a APPEND + 307: . STOP highest protocol among opcodes = 0 """ diff --git a/Lib/test/test_long.py b/Lib/test/test_long.py index c487bc5d0f61..e4ad4e7bb25b 100644 --- a/Lib/test/test_long.py +++ b/Lib/test/test_long.py @@ -283,6 +283,16 @@ class LongTest(unittest.TestCase): self.assertRaises(ValueError, int, '123\0') self.assertRaises(ValueError, int, '53', 40) + # trailing L should no longer be accepted... + self.assertRaises(ValueError, int, '123L') + self.assertRaises(ValueError, int, '123l') + self.assertRaises(ValueError, int, '0L') + self.assertRaises(ValueError, int, '-37L') + self.assertRaises(ValueError, int, '0x32L', 16) + self.assertRaises(ValueError, int, '1L', 21) + # ... but it's just a normal digit if base >= 22 + self.assertEqual(int('1L', 22), 43) + self.assertRaises(TypeError, int, 1, 12) # SF patch #1638879: embedded NULs were not detected with diff --git a/Misc/NEWS b/Misc/NEWS index 566bea5a67f5..8b2194eb495e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.0.1? Core and Builtins ----------------- +- Issue #4842: Don't allow trailing 'L' when constructing an integer + from a string. + - Issue #4991: os.fdopen now raises an OSError for invalid file descriptors. - Issue #4838: When a module is deallocated, free the memory backing the @@ -95,6 +98,9 @@ Core and Builtins Library ------- +- Issue #4842: Always append a trailing 'L' when pickling longs using + pickle protocol 0. When reading, the 'L' is optional. + - Issue #3826 and #4791: The socket module now closes the underlying socket appropriately when it is being used via socket.makefile() objects rather than delaying the close by waiting for garbage collection to do it. diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 6cc90b3f1e8b..02a3e447d907 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -846,8 +846,8 @@ save_int(PicklerObject *self, long x) /* Text-mode pickle, or long too big to fit in the 4-byte * signed BININT format: store as a string. */ - pdata[0] = LONG; /* use LONG for consistence with pickle.py */ - PyOS_snprintf(pdata + 1, sizeof(pdata) - 1, "%ld\n", x); + pdata[0] = LONG; /* use LONG for consistency with pickle.py */ + PyOS_snprintf(pdata + 1, sizeof(pdata) - 1, "%ldL\n", x); if (pickler_write(self, pdata, strlen(pdata)) < 0) return -1; } @@ -977,8 +977,9 @@ save_long(PicklerObject *self, PyObject *obj) else { char *string; - /* proto < 2: write the repr and newline. This is quadratic-time - (in the number of digits), in both directions. */ + /* proto < 2: write the repr and newline. This is quadratic-time (in + the number of digits), in both directions. We add a trailing 'L' + to the repr, for compatibility with Python 2.x. */ repr = PyObject_Repr(obj); if (repr == NULL) @@ -990,7 +991,7 @@ save_long(PicklerObject *self, PyObject *obj) if (pickler_write(self, &long_op, 1) < 0 || pickler_write(self, string, size) < 0 || - pickler_write(self, "\n", 1) < 0) + pickler_write(self, "L\n", 2) < 0) goto error; } @@ -2880,7 +2881,7 @@ static int load_long(UnpicklerObject *self) { PyObject *value; - char *s; + char *s, *ss; Py_ssize_t len; if ((len = unpickler_readline(self, &s)) < 0) @@ -2888,8 +2889,27 @@ load_long(UnpicklerObject *self) if (len < 2) return bad_readline(); - /* XXX: Should the base argument explicitly set to 10? */ - if ((value = PyLong_FromString(s, NULL, 0)) == NULL) + /* s[len-2] will usually be 'L' (and s[len-1] is '\n'); we need to remove + the 'L' before calling PyLong_FromString. In order to maintain + compatibility with Python 3.0.0, we don't actually *require* + the 'L' to be present. */ + if (s[len-2] == 'L') { + ss = (char *)PyMem_Malloc(len-1); + if (ss == NULL) { + PyErr_NoMemory(); + return -1; + } + strncpy(ss, s, len-2); + ss[len-2] = '\0'; + + /* XXX: Should the base argument explicitly set to 10? */ + value = PyLong_FromString(ss, NULL, 0); + PyMem_Free(ss); + } + else { + value = PyLong_FromString(s, NULL, 0); + } + if (value == NULL) return -1; PDATA_PUSH(self->stack, value, -1); diff --git a/Objects/longobject.c b/Objects/longobject.c index 40689fbee203..15b90eb53d50 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -1990,8 +1990,6 @@ digit beyond the first. goto onError; if (sign < 0) Py_SIZE(z) = -(Py_SIZE(z)); - if (*str == 'L' || *str == 'l') - str++; while (*str && isspace(Py_CHARMASK(*str))) str++; if (*str != '\0')