]> granicus.if.org Git - python/commitdiff
- Issue #5463: In struct module, remove deprecated overflow wrapping
authorMark Dickinson <dickinsm@gmail.com>
Sat, 21 Mar 2009 10:26:31 +0000 (10:26 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sat, 21 Mar 2009 10:26:31 +0000 (10:26 +0000)
  when packing an integer: for example, struct.pack('=L', -1) now
  raises struct.error instead of returning b'\xff\xff\xff\xff'.

  Thanks Andreas Schawo for the patch.

Lib/test/test_struct.py
Misc/ACKS
Misc/NEWS
Modules/_struct.c

index 3d5e0287281c55287ec5016d3b008ac79c9b0866..1d10b8f0c26e2030b341936c087d85b0d0fceddf 100644 (file)
@@ -2,8 +2,6 @@ import array
 import unittest
 import struct
 import warnings
-warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
-                        DeprecationWarning)
 
 from functools import wraps
 from test.support import TestFailed, verbose, run_unittest
@@ -17,11 +15,9 @@ try:
     import _struct
 except ImportError:
     PY_STRUCT_RANGE_CHECKING = 0
-    PY_STRUCT_OVERFLOW_MASKING = 1
     PY_STRUCT_FLOAT_COERCE = 2
 else:
     PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
-    PY_STRUCT_OVERFLOW_MASKING = getattr(_struct, '_PY_STRUCT_OVERFLOW_MASKING', 0)
     PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
 
 def string_reverse(s):
@@ -51,8 +47,7 @@ def deprecated_err(func, *args):
     except (struct.error, OverflowError):
         pass
     except DeprecationWarning:
-        if not PY_STRUCT_OVERFLOW_MASKING:
-            raise TestFailed("%s%s expected to raise DeprecationWarning" % (
+        raise TestFailed("%s%s expected to raise DeprecationWarning" % (
                 func.__name__, args))
     else:
         raise TestFailed("%s%s did not raise error" % (
@@ -471,11 +466,6 @@ class StructTest(unittest.TestCase):
                 self.check_float_coerce(endian + fmt, 1.0)
                 self.check_float_coerce(endian + fmt, 1.5)
 
-    def test_issue4228(self):
-        # Packing a long may yield either 32 or 64 bits
-        x = struct.pack('L', -1)[:4]
-        self.assertEqual(x, b'\xff'*4)
-
     def test_unpack_from(self):
         test_string = b'abcd01234'
         fmt = '4s'
index 7084f21f2870e4bb77c0216f1995fa7b1991a075..85bc8a1279411de8009403d4a9aa43fc1dd849ef 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -620,6 +620,7 @@ Ilya Sandler
 Ty Sarna
 Ben Sayer
 Michael Scharf
+Andreas Schawo
 Neil Schemenauer
 David Scherer
 Gregor Schmid
index 3e890f3cc4271c1f8ae658202f4e80e0df88bbdb..bad0a44474631086a7652a30a0527cab30c0fa69 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -44,6 +44,13 @@ Library
 - Issue #5016: FileIO.seekable() could return False if the file position
   was negative when truncated to a C int. Patch by Victor Stinner.
 
+Extension Modules
+-----------------
+
+- Issue #5463: In struct module, remove deprecated overflow wrapping
+  when packing an integer: struct.pack('=L', -1) now raises
+  struct.error instead of returning b'\xff\xff\xff\xff'.
+
 
 What's New in Python 3.1 alpha 1
 ================================
index 57441c4338c809161b1bc425190a9f0b34c65c77..3cc9fa067cf0a1a3e72bddb12dceaf902e1649eb 100644 (file)
 
 static PyTypeObject PyStructType;
 
-/* If PY_STRUCT_OVERFLOW_MASKING is defined, the struct module will wrap all input
-   numbers for explicit endians such that they fit in the given type, much
-   like explicit casting in C. A warning will be raised if the number did
-   not originally fit within the range of the requested type. If it is
-   not defined, then all range errors and overflow will be struct.error
-   exceptions. */
-
-#define PY_STRUCT_OVERFLOW_MASKING 1
-
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-static PyObject *pylong_ulong_mask = NULL;
-static PyObject *pyint_zero = NULL;
-#endif
-
 /* If PY_STRUCT_FLOAT_COERCE is defined, the struct module will allow float
    arguments for integer formats with a warning for backwards
    compatibility. */
@@ -237,107 +223,9 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
 
 #endif
 
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-
-/* Helper routine to get a Python integer and raise the appropriate error
-   if it isn't one */
-
-#define INT_OVERFLOW "struct integer overflow masking is deprecated"
 
-static int
-get_wrapped_long(PyObject *v, long *p)
-{
-       if (get_long(v, p) < 0) {
-               if (PyLong_Check(v) &&
-                   PyErr_ExceptionMatches(PyExc_OverflowError)) {
-                       PyObject *wrapped;
-                       long x;
-                       PyErr_Clear();
-#ifdef PY_STRUCT_FLOAT_COERCE
-                       if (PyFloat_Check(v)) {
-                               PyObject *o;
-                               int res;
-                               PyErr_Clear();
-                               if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
-                                       return -1;
-                               o = PyNumber_Long(v);
-                               if (o == NULL)
-                                       return -1;
-                               res = get_wrapped_long(o, p);
-                               Py_DECREF(o);
-                               return res;
-                       }
-#endif
-                       if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0)
-                               return -1;
-                       wrapped = PyNumber_And(v, pylong_ulong_mask);
-                       if (wrapped == NULL)
-                               return -1;
-                       x = (long)PyLong_AsUnsignedLong(wrapped);
-                       Py_DECREF(wrapped);
-                       if (x == -1 && PyErr_Occurred())
-                               return -1;
-                       *p = x;
-               } else {
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static int
-get_wrapped_ulong(PyObject *v, unsigned long *p)
-{
-       long x = (long)PyLong_AsUnsignedLong(v);
-       if (x == -1 && PyErr_Occurred()) {
-               PyObject *wrapped;
-               PyErr_Clear();
-#ifdef PY_STRUCT_FLOAT_COERCE
-               if (PyFloat_Check(v)) {
-                       PyObject *o;
-                       int res;
-                       PyErr_Clear();
-                       if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
-                               return -1;
-                       o = PyNumber_Long(v);
-                       if (o == NULL)
-                               return -1;
-                       res = get_wrapped_ulong(o, p);
-                       Py_DECREF(o);
-                       return res;
-               }
-#endif
-               wrapped = PyNumber_And(v, pylong_ulong_mask);
-               if (wrapped == NULL)
-                       return -1;
-               if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0) {
-                       Py_DECREF(wrapped);
-                       return -1;
-               }
-               x = (long)PyLong_AsUnsignedLong(wrapped);
-               Py_DECREF(wrapped);
-               if (x == -1 && PyErr_Occurred())
-                       return -1;
-       }
-       *p = (unsigned long)x;
-       return 0;
-}
-
-#define RANGE_ERROR(x, f, flag, mask) \
-       do { \
-               if (_range_error(f, flag) < 0) \
-                       return -1; \
-               else \
-                       (x) &= (mask); \
-       } while (0)
-
-#else
-
-#define get_wrapped_long get_long
-#define get_wrapped_ulong get_ulong
 #define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag)
 
-#endif
 
 /* Floating point helpers */
 
@@ -392,26 +280,7 @@ _range_error(const formatdef *f, int is_unsigned)
                        ~ largest,
                        largest);
        }
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-       {
-               PyObject *ptype, *pvalue, *ptraceback;
-               PyObject *msg;
-               int rval;
-               PyErr_Fetch(&ptype, &pvalue, &ptraceback);
-               assert(pvalue != NULL);
-               msg = PyObject_Str(pvalue);
-               Py_XDECREF(ptype);
-               Py_XDECREF(pvalue);
-               Py_XDECREF(ptraceback);
-               if (msg == NULL)
-                       return -1;
-               rval = PyErr_WarnEx(PyExc_DeprecationWarning,
-                                   _PyUnicode_AsString(msg), 2);
-               Py_DECREF(msg);
-               if (rval == 0)
-                       return 0;
-       }
-#endif
+
        return -1;
 }
 
@@ -673,7 +542,7 @@ np_uint(char *p, PyObject *v, const formatdef *f)
 {
        unsigned long x;
        unsigned int y;
-       if (get_wrapped_ulong(v, &x) < 0)
+       if (get_ulong(v, &x) < 0)
                return -1;
        y = (unsigned int)x;
 #if (SIZEOF_LONG > SIZEOF_INT)
@@ -698,7 +567,7 @@ static int
 np_ulong(char *p, PyObject *v, const formatdef *f)
 {
        unsigned long x;
-       if (get_wrapped_ulong(v, &x) < 0)
+       if (get_ulong(v, &x) < 0)
                return -1;
        memcpy(p, (char *)&x, sizeof x);
        return 0;
@@ -905,7 +774,7 @@ bp_int(char *p, PyObject *v, const formatdef *f)
 {
        long x;
        Py_ssize_t i;
-       if (get_wrapped_long(v, &x) < 0)
+       if (get_long(v, &x) < 0)
                return -1;
        i = f->size;
        if (i != SIZEOF_LONG) {
@@ -914,10 +783,6 @@ bp_int(char *p, PyObject *v, const formatdef *f)
 #if (SIZEOF_LONG != 4)
                else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
                        RANGE_ERROR(x, f, 0, 0xffffffffL);
-#endif
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-               else if ((i == 1) && (x < -128 || x > 127))
-                       RANGE_ERROR(x, f, 0, 0xffL);
 #endif
        }
        do {
@@ -932,7 +797,7 @@ bp_uint(char *p, PyObject *v, const formatdef *f)
 {
        unsigned long x;
        Py_ssize_t i;
-       if (get_wrapped_ulong(v, &x) < 0)
+       if (get_ulong(v, &x) < 0)
                return -1;
        i = f->size;
        if (i != SIZEOF_LONG) {
@@ -1015,14 +880,8 @@ bp_bool(char *p, PyObject *v, const formatdef *f)
 
 static formatdef bigendian_table[] = {
        {'x',   1,              0,              NULL},
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-       /* Native packers do range checking without overflow masking. */
-       {'b',   1,              0,              nu_byte,        bp_int},
-       {'B',   1,              0,              nu_ubyte,       bp_uint},
-#else
        {'b',   1,              0,              nu_byte,        np_byte},
        {'B',   1,              0,              nu_ubyte,       np_ubyte},
-#endif
        {'c',   1,              0,              nu_char,        np_char},
        {'s',   1,              0,              NULL},
        {'p',   1,              0,              NULL},
@@ -1133,7 +992,7 @@ lp_int(char *p, PyObject *v, const formatdef *f)
 {
        long x;
        Py_ssize_t i;
-       if (get_wrapped_long(v, &x) < 0)
+       if (get_long(v, &x) < 0)
                return -1;
        i = f->size;
        if (i != SIZEOF_LONG) {
@@ -1142,10 +1001,6 @@ lp_int(char *p, PyObject *v, const formatdef *f)
 #if (SIZEOF_LONG != 4)
                else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
                        RANGE_ERROR(x, f, 0, 0xffffffffL);
-#endif
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-               else if ((i == 1) && (x < -128 || x > 127))
-                       RANGE_ERROR(x, f, 0, 0xffL);
 #endif
        }
        do {
@@ -1160,7 +1015,7 @@ lp_uint(char *p, PyObject *v, const formatdef *f)
 {
        unsigned long x;
        Py_ssize_t i;
-       if (get_wrapped_ulong(v, &x) < 0)
+       if (get_ulong(v, &x) < 0)
                return -1;
        i = f->size;
        if (i != SIZEOF_LONG) {
@@ -1234,14 +1089,8 @@ lp_double(char *p, PyObject *v, const formatdef *f)
 
 static formatdef lilendian_table[] = {
        {'x',   1,              0,              NULL},
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-       /* Native packers do range checking without overflow masking. */
-       {'b',   1,              0,              nu_byte,        lp_int},
-       {'B',   1,              0,              nu_ubyte,       lp_uint},
-#else
        {'b',   1,              0,              nu_byte,        np_byte},
        {'B',   1,              0,              nu_ubyte,       np_ubyte},
-#endif
        {'c',   1,              0,              nu_char,        np_char},
        {'s',   1,              0,              NULL},
        {'p',   1,              0,              NULL},
@@ -2125,26 +1974,6 @@ PyInit__struct(void)
        if (PyType_Ready(&PyStructType) < 0)
                return NULL;
 
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-       if (pyint_zero == NULL) {
-               pyint_zero = PyLong_FromLong(0);
-               if (pyint_zero == NULL)
-                       return NULL;
-       }
-       if (pylong_ulong_mask == NULL) {
-#if (SIZEOF_LONG == 4)
-               pylong_ulong_mask = PyLong_FromString("FFFFFFFF", NULL, 16);
-#else
-               pylong_ulong_mask = PyLong_FromString("FFFFFFFFFFFFFFFF", NULL, 16);
-#endif
-               if (pylong_ulong_mask == NULL)
-                       return NULL;
-       }
-
-#else
-       /* This speed trick can't be used until overflow masking goes away, because
-          native endian always raises exceptions instead of overflow masking. */
-
        /* Check endian and swap in faster functions */
        {
                int one = 1;
@@ -2183,7 +2012,6 @@ PyInit__struct(void)
                        native++;
                }
        }
-#endif
 
        /* Add some symbolic constants to the module */
        if (StructError == NULL) {
@@ -2201,9 +2029,6 @@ PyInit__struct(void)
        PyModule_AddObject(m, "__version__", ver);
 
        PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1);
-#ifdef PY_STRUCT_OVERFLOW_MASKING
-       PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1);
-#endif
 #ifdef PY_STRUCT_FLOAT_COERCE
        PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
 #endif