diff -r afdb0e1a9dac Lib/test/test_marshal.py --- a/Lib/test/test_marshal.py Thu Jul 12 21:17:59 2012 +0200 +++ b/Lib/test/test_marshal.py Sat Jul 28 12:52:40 2012 +0200 @@ -7,6 +7,7 @@ import unittest import os import types +import struct class HelperMixin: def helper(self, sample, *extra): @@ -18,19 +19,38 @@ with open(support.TESTFN, "rb") as f: new = marshal.load(f) self.assertEqual(sample, new) + with open(support.TESTFN, "rb") as f: + return f.read() finally: support.unlink(support.TESTFN) +# The TYPE_INT64 code is used if one of the C 'long' or 'long long' +# types can hold 64 bits. +has_int64 = False +if struct.calcsize('l') >= 8: + has_int64 = True +try: + if struct.calcsize('q') >= 8: + has_int64 = True +except struct.error: + pass + class IntTestCase(unittest.TestCase, HelperMixin): def test_ints(self): # Test the full range of Python ints. - n = sys.maxsize - while n: - for expected in (-n, n): - self.helper(expected) - n = n >> 1 + self.assertEqual(self.helper(0), b'i\0\0\0\0') + for scale in range(100): + n = 1 << scale + for expected in (-n-1, -n, -n+1, n-1, n, n+1): + s = self.helper(expected) + if -(1 << 31) <= expected < (1 << 31): + self.assertEqual(s[0], ord('i')) + elif -(1 << 63) <= expected < (1 << 63) and has_int64: + self.assertEqual(s[0], ord('I')) + else: + self.assertEqual(s[0], ord('l')) - def test_int64(self): + def test_load_int64(self): # Simulate int marshaling on a 64-bit box. This is most interesting if # we're running the test on a 32-bit box, of course. diff -r afdb0e1a9dac Python/marshal.c --- a/Python/marshal.c Thu Jul 12 21:17:59 2012 +0200 +++ b/Python/marshal.c Sat Jul 28 12:52:40 2012 +0200 @@ -24,6 +24,22 @@ #define MAX_MARSHAL_STACK_DEPTH 2000 #endif +#if SIZEOF_LONG == 8 +# define USE_LONG64 1 +# define LONG64_T long +# define _PyLong_AsLong64 PyLong_AsLong +# define _PyLong_FromLong64 PyLong_FromLong +#elif HAVE_LONG_LONG && SIZEOF_LONG_LONG == 8 +# define USE_LONG64 1 +# define LONG64_T PY_LONG_LONG +# define _PyLong_AsLong64 PyLong_AsLongLong +# define _PyLong_FromLong64 PyLong_FromLongLong +#else +# if SIZEOF_LONG != 4 +# error unsupported configuration +# endif +#endif + #define TYPE_NULL '0' #define TYPE_NONE 'N' #define TYPE_FALSE 'F' @@ -121,9 +137,9 @@ w_byte((char)((x>>24) & 0xff), p); } -#if SIZEOF_LONG > 4 +#ifdef USE_LONG64 static void -w_long64(long x, WFILE *p) +w_long64(LONG64_T x, WFILE *p) { w_long(x, p); w_long(x>>32, p); @@ -209,26 +225,39 @@ w_byte(TYPE_TRUE, p); } else if (PyLong_CheckExact(v)) { - long x = PyLong_AsLong(v); - if ((x == -1) && PyErr_Occurred()) { - PyLongObject *ob = (PyLongObject *)v; + PyLongObject *ob = (PyLongObject *)v; +#ifdef USE_LONG64 + LONG64_T x = _PyLong_AsLong64(v); + if ((x == -1) && PyErr_Occurred()) { PyErr_Clear(); w_PyLong(ob, p); } else { -#if SIZEOF_LONG > 4 - long y = Py_ARITHMETIC_RIGHT_SHIFT(long, x, 31); - if (y && y != -1) { - w_byte(TYPE_INT64, p); - w_long64(x, p); - } - else -#endif - { + LONG64_T y = Py_ARITHMETIC_RIGHT_SHIFT(LONG64_T, x, 31); + if (y == 0 || y == -1) { + /* |x| fits in 31 bits */ w_byte(TYPE_INT, p); w_long(x, p); } + else { + /* |x| fits in 63 bits */ + w_byte(TYPE_INT64, p); + w_long64(x, p); + } } +#else /* USE_LONG64 */ + long x = PyLong_AsLong(v); + assert (sizeof(long) == 4); + if ((x == -1) && PyErr_Occurred()) { + PyErr_Clear(); + w_PyLong(ob, p); + } + else { + /* |x| fits in 31 bits */ + w_byte(TYPE_INT, p); + w_long(x, p); + } +#endif /* USE_LONG64 */ } else if (PyFloat_CheckExact(v)) { if (p->version > 1) { @@ -556,13 +585,6 @@ return x; } -/* r_long64 deals with the TYPE_INT64 code. On a machine with - sizeof(long) > 4, it returns a Python int object, else a Python long - object. Note that w_long64 writes out TYPE_INT if 32 bits is enough, - so there's no inefficiency here in returning a PyLong on 32-bit boxes - for everything written via TYPE_INT64 (i.e., if an int is written via - TYPE_INT64, it *needs* more than 32 bits). -*/ static PyObject * r_long64(RFILE *p) { @@ -571,9 +593,9 @@ long hi4 = r_long(p); if (!PyErr_Occurred()) { -#if SIZEOF_LONG > 4 - long x = (hi4 << 32) | (lo4 & 0xFFFFFFFFL); - result = PyLong_FromLong(x); +#if defined USE_LONG64 + LONG64_T x = ((LONG64_T)hi4 << 32) | ((LONG64_T)lo4 & 0xFFFFFFFFL); + result = _PyLong_FromLong64(x); #else unsigned char buf[8]; int one = 1;