From ae681df4d8a0edf22a60e853d519c42012c31983 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 21 Mar 2009 10:26:31 +0000 Subject: - Issue #5463: In struct module, remove deprecated overflow wrapping 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 | 12 +-- Misc/ACKS | 1 + Misc/NEWS | 7 ++ Modules/_struct.c | 189 ++---------------------------------------------- 4 files changed, 16 insertions(+), 193 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 3d5e028..1d10b8f 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -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' diff --git a/Misc/ACKS b/Misc/ACKS index 7084f21..85bc8a1 100644 --- 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 diff --git a/Misc/NEWS b/Misc/NEWS index 3e890f3..bad0a44 100644 --- 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 ================================ diff --git a/Modules/_struct.c b/Modules/_struct.c index 57441c4..3cc9fa0 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -12,20 +12,6 @@ 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) { @@ -915,10 +784,6 @@ bp_int(char *p, PyObject *v, const formatdef *f) 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 { p[--i] = (char)x; @@ -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) { @@ -1143,10 +1002,6 @@ lp_int(char *p, PyObject *v, const formatdef *f) 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 { *p++ = (char)x; @@ -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 -- cgit v0.12