mirror of
https://github.com/python/cpython.git
synced 2024-11-24 18:34:43 +08:00
- 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.
This commit is contained in:
parent
e43b060b05
commit
ae681df4d8
@ -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'
|
||||
|
@ -620,6 +620,7 @@ Ilya Sandler
|
||||
Ty Sarna
|
||||
Ben Sayer
|
||||
Michael Scharf
|
||||
Andreas Schawo
|
||||
Neil Schemenauer
|
||||
David Scherer
|
||||
Gregor Schmid
|
||||
|
@ -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
|
||||
================================
|
||||
|
@ -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) {
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user