mirror of
https://github.com/python/cpython.git
synced 2025-10-10 00:43:41 +00: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
4 changed files with 16 additions and 193 deletions
|
@ -2,8 +2,6 @@ import array
|
||||||
import unittest
|
import unittest
|
||||||
import struct
|
import struct
|
||||||
import warnings
|
import warnings
|
||||||
warnings.filterwarnings("ignore", "struct integer overflow masking is deprecated",
|
|
||||||
DeprecationWarning)
|
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from test.support import TestFailed, verbose, run_unittest
|
from test.support import TestFailed, verbose, run_unittest
|
||||||
|
@ -17,11 +15,9 @@ try:
|
||||||
import _struct
|
import _struct
|
||||||
except ImportError:
|
except ImportError:
|
||||||
PY_STRUCT_RANGE_CHECKING = 0
|
PY_STRUCT_RANGE_CHECKING = 0
|
||||||
PY_STRUCT_OVERFLOW_MASKING = 1
|
|
||||||
PY_STRUCT_FLOAT_COERCE = 2
|
PY_STRUCT_FLOAT_COERCE = 2
|
||||||
else:
|
else:
|
||||||
PY_STRUCT_RANGE_CHECKING = getattr(_struct, '_PY_STRUCT_RANGE_CHECKING', 0)
|
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)
|
PY_STRUCT_FLOAT_COERCE = getattr(_struct, '_PY_STRUCT_FLOAT_COERCE', 0)
|
||||||
|
|
||||||
def string_reverse(s):
|
def string_reverse(s):
|
||||||
|
@ -51,7 +47,6 @@ def deprecated_err(func, *args):
|
||||||
except (struct.error, OverflowError):
|
except (struct.error, OverflowError):
|
||||||
pass
|
pass
|
||||||
except DeprecationWarning:
|
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))
|
func.__name__, args))
|
||||||
else:
|
else:
|
||||||
|
@ -471,11 +466,6 @@ class StructTest(unittest.TestCase):
|
||||||
self.check_float_coerce(endian + fmt, 1.0)
|
self.check_float_coerce(endian + fmt, 1.0)
|
||||||
self.check_float_coerce(endian + fmt, 1.5)
|
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):
|
def test_unpack_from(self):
|
||||||
test_string = b'abcd01234'
|
test_string = b'abcd01234'
|
||||||
fmt = '4s'
|
fmt = '4s'
|
||||||
|
|
|
@ -620,6 +620,7 @@ Ilya Sandler
|
||||||
Ty Sarna
|
Ty Sarna
|
||||||
Ben Sayer
|
Ben Sayer
|
||||||
Michael Scharf
|
Michael Scharf
|
||||||
|
Andreas Schawo
|
||||||
Neil Schemenauer
|
Neil Schemenauer
|
||||||
David Scherer
|
David Scherer
|
||||||
Gregor Schmid
|
Gregor Schmid
|
||||||
|
|
|
@ -44,6 +44,13 @@ Library
|
||||||
- Issue #5016: FileIO.seekable() could return False if the file position
|
- Issue #5016: FileIO.seekable() could return False if the file position
|
||||||
was negative when truncated to a C int. Patch by Victor Stinner.
|
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
|
What's New in Python 3.1 alpha 1
|
||||||
================================
|
================================
|
||||||
|
|
|
@ -12,20 +12,6 @@
|
||||||
|
|
||||||
static PyTypeObject PyStructType;
|
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
|
/* If PY_STRUCT_FLOAT_COERCE is defined, the struct module will allow float
|
||||||
arguments for integer formats with a warning for backwards
|
arguments for integer formats with a warning for backwards
|
||||||
compatibility. */
|
compatibility. */
|
||||||
|
@ -237,107 +223,9 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
|
||||||
|
|
||||||
#endif
|
#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)
|
#define RANGE_ERROR(x, f, flag, mask) return _range_error(f, flag)
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Floating point helpers */
|
/* Floating point helpers */
|
||||||
|
|
||||||
|
@ -392,26 +280,7 @@ _range_error(const formatdef *f, int is_unsigned)
|
||||||
~ largest,
|
~ largest,
|
||||||
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,7 +542,7 @@ np_uint(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
unsigned int y;
|
unsigned int y;
|
||||||
if (get_wrapped_ulong(v, &x) < 0)
|
if (get_ulong(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
y = (unsigned int)x;
|
y = (unsigned int)x;
|
||||||
#if (SIZEOF_LONG > SIZEOF_INT)
|
#if (SIZEOF_LONG > SIZEOF_INT)
|
||||||
|
@ -698,7 +567,7 @@ static int
|
||||||
np_ulong(char *p, PyObject *v, const formatdef *f)
|
np_ulong(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
if (get_wrapped_ulong(v, &x) < 0)
|
if (get_ulong(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
memcpy(p, (char *)&x, sizeof x);
|
memcpy(p, (char *)&x, sizeof x);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -905,7 +774,7 @@ bp_int(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
long x;
|
long x;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
if (get_wrapped_long(v, &x) < 0)
|
if (get_long(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
i = f->size;
|
i = f->size;
|
||||||
if (i != SIZEOF_LONG) {
|
if (i != SIZEOF_LONG) {
|
||||||
|
@ -914,10 +783,6 @@ bp_int(char *p, PyObject *v, const formatdef *f)
|
||||||
#if (SIZEOF_LONG != 4)
|
#if (SIZEOF_LONG != 4)
|
||||||
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
|
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
|
||||||
RANGE_ERROR(x, f, 0, 0xffffffffL);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
@ -932,7 +797,7 @@ bp_uint(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
if (get_wrapped_ulong(v, &x) < 0)
|
if (get_ulong(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
i = f->size;
|
i = f->size;
|
||||||
if (i != SIZEOF_LONG) {
|
if (i != SIZEOF_LONG) {
|
||||||
|
@ -1015,14 +880,8 @@ bp_bool(char *p, PyObject *v, const formatdef *f)
|
||||||
|
|
||||||
static formatdef bigendian_table[] = {
|
static formatdef bigendian_table[] = {
|
||||||
{'x', 1, 0, NULL},
|
{'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_byte, np_byte},
|
||||||
{'B', 1, 0, nu_ubyte, np_ubyte},
|
{'B', 1, 0, nu_ubyte, np_ubyte},
|
||||||
#endif
|
|
||||||
{'c', 1, 0, nu_char, np_char},
|
{'c', 1, 0, nu_char, np_char},
|
||||||
{'s', 1, 0, NULL},
|
{'s', 1, 0, NULL},
|
||||||
{'p', 1, 0, NULL},
|
{'p', 1, 0, NULL},
|
||||||
|
@ -1133,7 +992,7 @@ lp_int(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
long x;
|
long x;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
if (get_wrapped_long(v, &x) < 0)
|
if (get_long(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
i = f->size;
|
i = f->size;
|
||||||
if (i != SIZEOF_LONG) {
|
if (i != SIZEOF_LONG) {
|
||||||
|
@ -1142,10 +1001,6 @@ lp_int(char *p, PyObject *v, const formatdef *f)
|
||||||
#if (SIZEOF_LONG != 4)
|
#if (SIZEOF_LONG != 4)
|
||||||
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
|
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
|
||||||
RANGE_ERROR(x, f, 0, 0xffffffffL);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
do {
|
do {
|
||||||
|
@ -1160,7 +1015,7 @@ lp_uint(char *p, PyObject *v, const formatdef *f)
|
||||||
{
|
{
|
||||||
unsigned long x;
|
unsigned long x;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
if (get_wrapped_ulong(v, &x) < 0)
|
if (get_ulong(v, &x) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
i = f->size;
|
i = f->size;
|
||||||
if (i != SIZEOF_LONG) {
|
if (i != SIZEOF_LONG) {
|
||||||
|
@ -1234,14 +1089,8 @@ lp_double(char *p, PyObject *v, const formatdef *f)
|
||||||
|
|
||||||
static formatdef lilendian_table[] = {
|
static formatdef lilendian_table[] = {
|
||||||
{'x', 1, 0, NULL},
|
{'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_byte, np_byte},
|
||||||
{'B', 1, 0, nu_ubyte, np_ubyte},
|
{'B', 1, 0, nu_ubyte, np_ubyte},
|
||||||
#endif
|
|
||||||
{'c', 1, 0, nu_char, np_char},
|
{'c', 1, 0, nu_char, np_char},
|
||||||
{'s', 1, 0, NULL},
|
{'s', 1, 0, NULL},
|
||||||
{'p', 1, 0, NULL},
|
{'p', 1, 0, NULL},
|
||||||
|
@ -2125,26 +1974,6 @@ PyInit__struct(void)
|
||||||
if (PyType_Ready(&PyStructType) < 0)
|
if (PyType_Ready(&PyStructType) < 0)
|
||||||
return NULL;
|
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 */
|
/* Check endian and swap in faster functions */
|
||||||
{
|
{
|
||||||
int one = 1;
|
int one = 1;
|
||||||
|
@ -2183,7 +2012,6 @@ PyInit__struct(void)
|
||||||
native++;
|
native++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Add some symbolic constants to the module */
|
/* Add some symbolic constants to the module */
|
||||||
if (StructError == NULL) {
|
if (StructError == NULL) {
|
||||||
|
@ -2201,9 +2029,6 @@ PyInit__struct(void)
|
||||||
PyModule_AddObject(m, "__version__", ver);
|
PyModule_AddObject(m, "__version__", ver);
|
||||||
|
|
||||||
PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1);
|
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
|
#ifdef PY_STRUCT_FLOAT_COERCE
|
||||||
PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
|
PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue