From bbf4df456007c226de891bcbfdd7d299841a5de4 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Thu, 13 Oct 2022 15:59:08 -0400 Subject: [PATCH 01/17] fix wrong error messages in struct.pack --- Modules/_struct.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Modules/_struct.c b/Modules/_struct.c index f9bac34c1e38b8..6db7069c9100f4 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -964,6 +964,13 @@ bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) 0, /* little_endian */ 1 /* signed */); Py_DECREF(v); + if (res == -1 && PyErr_Occurred()) { + PyErr_Format(state->StructError, + "longlong format requires %lld <= number <= %lld", + LLONG_MIN, + LLONG_MAX); + return -1; + } return res; } @@ -980,6 +987,12 @@ bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f 0, /* little_endian */ 0 /* signed */); Py_DECREF(v); + if (res == -1 && PyErr_Occurred()) { + PyErr_Format(state->StructError, + "longlong format requires 0 <= number <= %llu", + ULLONG_MAX); + return -1; + } return res; } From 64e17b981dcb48994f79687f936247f31a7e24a4 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 13 Oct 2022 22:13:54 +0000 Subject: [PATCH 02/17] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2022-10-13-22-13-54.gh-issue-98248.lwyygy.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-10-13-22-13-54.gh-issue-98248.lwyygy.rst diff --git a/Misc/NEWS.d/next/Library/2022-10-13-22-13-54.gh-issue-98248.lwyygy.rst b/Misc/NEWS.d/next/Library/2022-10-13-22-13-54.gh-issue-98248.lwyygy.rst new file mode 100644 index 00000000000000..347f6e160335e2 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-10-13-22-13-54.gh-issue-98248.lwyygy.rst @@ -0,0 +1 @@ +Provide informative error messages in :func:`struct.pack` when its integral arguments are not in range. From 18fbcbcbff791ea1481463b8d51d675cd827d838 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Thu, 13 Oct 2022 19:01:35 -0400 Subject: [PATCH 03/17] Provide informative error messages in struct.pack --- Modules/_struct.c | 91 +++++++++++++++++++++++++++++------------------ 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index 6db7069c9100f4..a75f97bf883dcc 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -545,9 +545,7 @@ static int np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(state, v, &x) < 0) - return -1; - if (x < -128 || x > 127) { + if (get_long(state, v, &x) < 0 || x < -128 || x > 127) { PyErr_SetString(state->StructError, "byte format requires -128 <= number <= 127"); return -1; @@ -560,9 +558,7 @@ static int np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(state, v, &x) < 0) - return -1; - if (x < 0 || x > 255) { + if (get_long(state, v, &x) < 0 || x < 0 || x > 255) { PyErr_SetString(state->StructError, "ubyte format requires 0 <= number <= 255"); return -1; @@ -588,9 +584,7 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; short y; - if (get_long(state, v, &x) < 0) - return -1; - if (x < SHRT_MIN || x > SHRT_MAX) { + if (get_long(state, v, &x) < 0 || x < SHRT_MIN || x > SHRT_MAX) { PyErr_Format(state->StructError, "short format requires %d <= number <= %d", (int)SHRT_MIN, (int)SHRT_MAX); @@ -606,9 +600,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; unsigned short y; - if (get_long(state, v, &x) < 0) - return -1; - if (x < 0 || x > USHRT_MAX) { + if (get_long(state, v, &x) < 0 || x < 0 || x > USHRT_MAX) { PyErr_Format(state->StructError, "ushort format requires 0 <= number <= %u", (unsigned int)USHRT_MAX); @@ -624,8 +616,9 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; int y; - if (get_long(state, v, &x) < 0) - return -1; + if (get_long(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } #if (SIZEOF_LONG > SIZEOF_INT) if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX))) RANGE_ERROR(state, x, f, 0, -1); @@ -640,8 +633,9 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; unsigned int y; - if (get_ulong(state, v, &x) < 0) - return -1; + if (get_ulong(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + } y = (unsigned int)x; #if (SIZEOF_LONG > SIZEOF_INT) if (x > ((unsigned long)UINT_MAX)) @@ -655,8 +649,9 @@ static int np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(state, v, &x) < 0) - return -1; + if (get_long(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -665,8 +660,9 @@ static int np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; - if (get_ulong(state, v, &x) < 0) - return -1; + if (get_ulong(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -675,8 +671,9 @@ static int np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { Py_ssize_t x; - if (get_ssize_t(state, v, &x) < 0) - return -1; + if (get_ssize_t(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -685,8 +682,9 @@ static int np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { size_t x; - if (get_size_t(state, v, &x) < 0) - return -1; + if (get_size_t(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 1, (size_t)-1); + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -695,8 +693,12 @@ static int np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long long x; - if (get_longlong(state, v, &x) < 0) + if (get_longlong(state, v, &x) < 0) { + PyErr_Format(state->StructError, + "longlong format requires %lld <= number <= %lld", + LLONG_MAX); return -1; + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -705,8 +707,12 @@ static int np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long long x; - if (get_ulonglong(state, v, &x) < 0) + if (get_ulonglong(state, v, &x) < 0) { + PyErr_Format(state->StructError, + "ulonglong format requires 0 <= number <= %llu", + ULLONG_MAX); return -1; + } memcpy(p, (char *)&x, sizeof x); return 0; } @@ -911,8 +917,9 @@ bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_long(state, v, &x) < 0) - return -1; + if (get_long(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) @@ -935,8 +942,9 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_ulong(state, v, &x) < 0) - return -1; + if (get_ulong(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + } i = f->size; if (i != SIZEOF_LONG) { unsigned long maxint = 1; @@ -1161,8 +1169,9 @@ lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_long(state, v, &x) < 0) - return -1; + if (get_long(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) @@ -1185,8 +1194,9 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long x; Py_ssize_t i; unsigned char *q = (unsigned char *)p; - if (get_ulong(state, v, &x) < 0) - return -1; + if (get_ulong(state, v, &x) < 0) { + RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + } i = f->size; if (i != SIZEOF_LONG) { unsigned long maxint = 1; @@ -1214,6 +1224,13 @@ lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) 1, /* little_endian */ 1 /* signed */); Py_DECREF(v); + if (res == -1 && PyErr_Occurred()) { + PyErr_Format(state->StructError, + "longlong format requires %lld <= number <= %lld", + LLONG_MIN, + LLONG_MAX); + return -1; + } return res; } @@ -1230,6 +1247,12 @@ lp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f 1, /* little_endian */ 0 /* signed */); Py_DECREF(v); + if (res == -1 && PyErr_Occurred()) { + PyErr_Format(state->StructError, + "ulonglong format requires 0 <= number <= %llu", + ULLONG_MAX); + return -1; + } return res; } From ebfe2f039551231601dca0cfabb86da749833087 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Thu, 13 Oct 2022 19:33:36 -0400 Subject: [PATCH 04/17] Normalizing error messages of struct.pack --- Lib/test/test_struct.py | 4 ++-- Modules/_struct.c | 37 +++++++++++++++++-------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index b0f11af1a7892e..cb1f1946bbc1f2 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -725,7 +725,7 @@ def test_issue35714(self): @support.cpython_only def test_issue45034_unsigned(self): _testcapi = import_helper.import_module('_testcapi') - error_msg = f'ushort format requires 0 <= number <= {_testcapi.USHRT_MAX}' + error_msg = f'\'H\' format requires 0 <= number <= {_testcapi.USHRT_MAX}' with self.assertRaisesRegex(struct.error, error_msg): struct.pack('H', 70000) # too large with self.assertRaisesRegex(struct.error, error_msg): @@ -734,7 +734,7 @@ def test_issue45034_unsigned(self): @support.cpython_only def test_issue45034_signed(self): _testcapi = import_helper.import_module('_testcapi') - error_msg = f'short format requires {_testcapi.SHRT_MIN} <= number <= {_testcapi.SHRT_MAX}' + error_msg = f'\'h\' format requires {_testcapi.SHRT_MIN} <= number <= {_testcapi.SHRT_MAX}' with self.assertRaisesRegex(struct.error, error_msg): struct.pack('h', 70000) # too large with self.assertRaisesRegex(struct.error, error_msg): diff --git a/Modules/_struct.c b/Modules/_struct.c index a75f97bf883dcc..f7058a81374b25 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -546,9 +546,7 @@ np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0 || x < -128 || x > 127) { - PyErr_SetString(state->StructError, - "byte format requires -128 <= number <= 127"); - return -1; + RANGE_ERROR(state, x, f, 0, (unsigned char)-1); } *p = (char)x; return 0; @@ -559,9 +557,7 @@ np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0 || x < 0 || x > 255) { - PyErr_SetString(state->StructError, - "ubyte format requires 0 <= number <= 255"); - return -1; + RANGE_ERROR(state, x, f, 1, (unsigned char)-1); } *(unsigned char *)p = (unsigned char)x; return 0; @@ -585,10 +581,7 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; short y; if (get_long(state, v, &x) < 0 || x < SHRT_MIN || x > SHRT_MAX) { - PyErr_Format(state->StructError, - "short format requires %d <= number <= %d", - (int)SHRT_MIN, (int)SHRT_MAX); - return -1; + RANGE_ERROR(state, x, f, 0, (unsigned short)-1); } y = (short)x; memcpy(p, (char *)&y, sizeof y); @@ -601,10 +594,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; unsigned short y; if (get_long(state, v, &x) < 0 || x < 0 || x > USHRT_MAX) { - PyErr_Format(state->StructError, - "ushort format requires 0 <= number <= %u", - (unsigned int)USHRT_MAX); - return -1; + RANGE_ERROR(state, x, f, 1, (unsigned short)-1); } y = (unsigned short)x; memcpy(p, (char *)&y, sizeof y); @@ -695,7 +685,9 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long long x; if (get_longlong(state, v, &x) < 0) { PyErr_Format(state->StructError, - "longlong format requires %lld <= number <= %lld", + "'%c' format requires %lld <= number <= %lld", + f->format, + LLONG_MIN, LLONG_MAX); return -1; } @@ -709,7 +701,8 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f unsigned long long x; if (get_ulonglong(state, v, &x) < 0) { PyErr_Format(state->StructError, - "ulonglong format requires 0 <= number <= %llu", + "'%c' format requires 0 <= number <= %llu", + f->format, ULLONG_MAX); return -1; } @@ -974,7 +967,8 @@ bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_DECREF(v); if (res == -1 && PyErr_Occurred()) { PyErr_Format(state->StructError, - "longlong format requires %lld <= number <= %lld", + "'%c' format requires %lld <= number <= %lld", + f->format, LLONG_MIN, LLONG_MAX); return -1; @@ -997,7 +991,8 @@ bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f Py_DECREF(v); if (res == -1 && PyErr_Occurred()) { PyErr_Format(state->StructError, - "longlong format requires 0 <= number <= %llu", + "'%c' format requires 0 <= number <= %llu", + f->format, ULLONG_MAX); return -1; } @@ -1226,7 +1221,8 @@ lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_DECREF(v); if (res == -1 && PyErr_Occurred()) { PyErr_Format(state->StructError, - "longlong format requires %lld <= number <= %lld", + "'%c' format requires %lld <= number <= %lld", + f->format, LLONG_MIN, LLONG_MAX); return -1; @@ -1249,7 +1245,8 @@ lp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f Py_DECREF(v); if (res == -1 && PyErr_Occurred()) { PyErr_Format(state->StructError, - "ulonglong format requires 0 <= number <= %llu", + "'%c' format requires 0 <= number <= %llu", + f->format, ULLONG_MAX); return -1; } From bfd4a850d6742f906c5bfcaa007bf7c8aa26f212 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Thu, 13 Oct 2022 22:53:07 -0400 Subject: [PATCH 05/17] Update test cases --- Lib/test/test_struct.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index cb1f1946bbc1f2..b9569ee9755331 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -740,6 +740,35 @@ def test_issue45034_signed(self): with self.assertRaisesRegex(struct.error, error_msg): struct.pack('h', -70000) # too small + @support.cpython_only + def test_issue92848(self): + def test_error_msg(prefix, int_type, is_unsigned): + fmt_str = prefix + int_type + size = struct.calcsize(fmt_str) + if is_unsigned: + max_ = 2 ** (size * 8) - 1 + min_ = 0 + else: + max_ = 2 ** (size * 8 - 1) - 1 + min_ = -2 ** (size * 8 - 1) + error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}" + for value in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]: + with self.assertRaisesRegex(struct.error, error_msg): + struct.pack(fmt_str, value) + + for int_type in 'BHILQ': + for prefix in '@=<>': + test_error_msg(prefix, int_type, True) + + for int_type in 'bhilq': + for prefix in '@=<>': + test_error_msg(prefix, int_type, False) + + int_type = 'N' + test_error_msg("@", int_type, True) + + int_type = 'n' + test_error_msg("@", int_type, False) class UnpackIteratorTest(unittest.TestCase): """ From b04dcb61487a6f5692d4a9cdce7033ec2e20bb2d Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Thu, 13 Oct 2022 22:57:07 -0400 Subject: [PATCH 06/17] Remove some previous test methods since they are covered by new test methods --- Lib/test/test_struct.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index b9569ee9755331..c8db51964883f1 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -722,24 +722,6 @@ def test_issue35714(self): 'embedded null character'): struct.calcsize(s) - @support.cpython_only - def test_issue45034_unsigned(self): - _testcapi = import_helper.import_module('_testcapi') - error_msg = f'\'H\' format requires 0 <= number <= {_testcapi.USHRT_MAX}' - with self.assertRaisesRegex(struct.error, error_msg): - struct.pack('H', 70000) # too large - with self.assertRaisesRegex(struct.error, error_msg): - struct.pack('H', -1) # too small - - @support.cpython_only - def test_issue45034_signed(self): - _testcapi = import_helper.import_module('_testcapi') - error_msg = f'\'h\' format requires {_testcapi.SHRT_MIN} <= number <= {_testcapi.SHRT_MAX}' - with self.assertRaisesRegex(struct.error, error_msg): - struct.pack('h', 70000) # too large - with self.assertRaisesRegex(struct.error, error_msg): - struct.pack('h', -70000) # too small - @support.cpython_only def test_issue92848(self): def test_error_msg(prefix, int_type, is_unsigned): From c15fe13f7115910dcf75481b432ffea2ff9dbb0a Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Fri, 14 Oct 2022 09:32:04 -0400 Subject: [PATCH 07/17] reorder for loops --- Lib/test/test_struct.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index c8db51964883f1..c48883e9cce4d1 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -738,12 +738,10 @@ def test_error_msg(prefix, int_type, is_unsigned): with self.assertRaisesRegex(struct.error, error_msg): struct.pack(fmt_str, value) - for int_type in 'BHILQ': - for prefix in '@=<>': + for prefix in '@=<>': + for int_type in 'BHILQ': test_error_msg(prefix, int_type, True) - - for int_type in 'bhilq': - for prefix in '@=<>': + for int_type in 'bhilq': test_error_msg(prefix, int_type, False) int_type = 'N' From 117a158cc50739444599efb1a7e469cd5252c11f Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Fri, 14 Oct 2022 09:34:18 -0400 Subject: [PATCH 08/17] rename a local variable --- Lib/test/test_struct.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index c48883e9cce4d1..4b91ec00fa8246 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -734,9 +734,9 @@ def test_error_msg(prefix, int_type, is_unsigned): max_ = 2 ** (size * 8 - 1) - 1 min_ = -2 ** (size * 8 - 1) error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}" - for value in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]: + for number in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]: with self.assertRaisesRegex(struct.error, error_msg): - struct.pack(fmt_str, value) + struct.pack(fmt_str, number) for prefix in '@=<>': for int_type in 'BHILQ': From 2981e10c56f73ae32959b7fc11f87ff968c4f98b Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Fri, 14 Oct 2022 09:39:20 -0400 Subject: [PATCH 09/17] use subtests --- Lib/test/test_struct.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 4b91ec00fa8246..e10cb2d4c58028 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -735,8 +735,9 @@ def test_error_msg(prefix, int_type, is_unsigned): min_ = -2 ** (size * 8 - 1) error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}" for number in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]: - with self.assertRaisesRegex(struct.error, error_msg): - struct.pack(fmt_str, number) + with self.subTest(format_str=fmt_str, number=number): + with self.assertRaisesRegex(struct.error, error_msg): + struct.pack(fmt_str, number) for prefix in '@=<>': for int_type in 'BHILQ': From ec8b417aa7bc77eedda05b1a71042118db5e8e80 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Sun, 16 Oct 2022 09:12:31 -0400 Subject: [PATCH 10/17] update new test cases --- Lib/test/test_struct.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index e10cb2d4c58028..efe92419ea6d92 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -738,6 +738,11 @@ def test_error_msg(prefix, int_type, is_unsigned): with self.subTest(format_str=fmt_str, number=number): with self.assertRaisesRegex(struct.error, error_msg): struct.pack(fmt_str, number) + error_msg = "required argument is not an integer" + not_number = "" + with self.subTest(format_str=fmt_str, number=not_number): + with self.assertRaisesRegex(struct.error, error_msg): + struct.pack(fmt_str, not_number) for prefix in '@=<>': for int_type in 'BHILQ': From 5f574e1793f660a7973e22632e56964aabf291ef Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Sun, 16 Oct 2022 10:22:20 -0400 Subject: [PATCH 11/17] fix error messages for non-integral arguments --- Modules/_struct.c | 110 +++++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index f7058a81374b25..59e5300879c1c1 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -167,9 +167,6 @@ get_long(_structmodulestate *state, PyObject *v, long *p) x = PyLong_AsLong(v); Py_DECREF(v); if (x == (long)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -191,9 +188,6 @@ get_ulong(_structmodulestate *state, PyObject *v, unsigned long *p) x = PyLong_AsUnsignedLong(v); Py_DECREF(v); if (x == (unsigned long)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -214,9 +208,6 @@ get_longlong(_structmodulestate *state, PyObject *v, long long *p) x = PyLong_AsLongLong(v); Py_DECREF(v); if (x == (long long)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -237,9 +228,6 @@ get_ulonglong(_structmodulestate *state, PyObject *v, unsigned long long *p) x = PyLong_AsUnsignedLongLong(v); Py_DECREF(v); if (x == (unsigned long long)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -260,9 +248,6 @@ get_ssize_t(_structmodulestate *state, PyObject *v, Py_ssize_t *p) x = PyLong_AsSsize_t(v); Py_DECREF(v); if (x == (Py_ssize_t)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -283,9 +268,6 @@ get_size_t(_structmodulestate *state, PyObject *v, size_t *p) x = PyLong_AsSize_t(v); Py_DECREF(v); if (x == (size_t)-1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) - PyErr_SetString(state->StructError, - "argument out of range"); return -1; } *p = x; @@ -546,7 +528,10 @@ np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0 || x < -128 || x > 127) { - RANGE_ERROR(state, x, f, 0, (unsigned char)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned char)-1); + } + return -1; } *p = (char)x; return 0; @@ -557,7 +542,10 @@ np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0 || x < 0 || x > 255) { - RANGE_ERROR(state, x, f, 1, (unsigned char)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned char)-1); + } + return -1; } *(unsigned char *)p = (unsigned char)x; return 0; @@ -581,7 +569,10 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; short y; if (get_long(state, v, &x) < 0 || x < SHRT_MIN || x > SHRT_MAX) { - RANGE_ERROR(state, x, f, 0, (unsigned short)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned short)-1); + } + return -1; } y = (short)x; memcpy(p, (char *)&y, sizeof y); @@ -594,7 +585,10 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; unsigned short y; if (get_long(state, v, &x) < 0 || x < 0 || x > USHRT_MAX) { - RANGE_ERROR(state, x, f, 1, (unsigned short)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned short)-1); + } + return -1; } y = (unsigned short)x; memcpy(p, (char *)&y, sizeof y); @@ -607,7 +601,10 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; int y; if (get_long(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } + return -1; } #if (SIZEOF_LONG > SIZEOF_INT) if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX))) @@ -624,7 +621,10 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long x; unsigned int y; if (get_ulong(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + } + return -1; } y = (unsigned int)x; #if (SIZEOF_LONG > SIZEOF_INT) @@ -640,7 +640,10 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + } + return -1; } memcpy(p, (char *)&x, sizeof x); return 0; @@ -651,7 +654,10 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; if (get_ulong(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + } + return -1; } memcpy(p, (char *)&x, sizeof x); return 0; @@ -662,7 +668,10 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { Py_ssize_t x; if (get_ssize_t(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + } + return -1; } memcpy(p, (char *)&x, sizeof x); return 0; @@ -673,7 +682,10 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { size_t x; if (get_size_t(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 1, (size_t)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (size_t)-1); + } + return -1; } memcpy(p, (char *)&x, sizeof x); return 0; @@ -684,11 +696,13 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long long x; if (get_longlong(state, v, &x) < 0) { - PyErr_Format(state->StructError, - "'%c' format requires %lld <= number <= %lld", - f->format, - LLONG_MIN, - LLONG_MAX); + if (!PyErr_ExceptionMatches(state->StructError)) { + PyErr_Format(state->StructError, + "'%c' format requires %lld <= number <= %lld", + f->format, + LLONG_MIN, + LLONG_MAX); + } return -1; } memcpy(p, (char *)&x, sizeof x); @@ -700,10 +714,12 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f { unsigned long long x; if (get_ulonglong(state, v, &x) < 0) { - PyErr_Format(state->StructError, - "'%c' format requires 0 <= number <= %llu", - f->format, - ULLONG_MAX); + if (!PyErr_ExceptionMatches(state->StructError)) { + PyErr_Format(state->StructError, + "'%c' format requires 0 <= number <= %llu", + f->format, + ULLONG_MAX); + } return -1; } memcpy(p, (char *)&x, sizeof x); @@ -911,7 +927,10 @@ bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } + return -1; } i = f->size; if (i != SIZEOF_LONG) { @@ -936,7 +955,10 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + } + return -1; } i = f->size; if (i != SIZEOF_LONG) { @@ -1165,7 +1187,10 @@ lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + } + return -1; } i = f->size; if (i != SIZEOF_LONG) { @@ -1190,7 +1215,10 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { - RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + if (!PyErr_ExceptionMatches(state->StructError)) { + RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + } + return -1; } i = f->size; if (i != SIZEOF_LONG) { From 61c016be078524ccc08a3955d6aa48f7a23588d1 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Tue, 25 Oct 2022 15:58:27 -0400 Subject: [PATCH 12/17] fix typos --- Modules/_struct.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index 59e5300879c1c1..69ed3dd291047e 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -622,7 +622,7 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned int y; if (get_ulong(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + RANGE_ERROR(state, x, f, 1, (unsigned int)-1); } return -1; } @@ -669,7 +669,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t x; if (get_ssize_t(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + RANGE_ERROR(state, x, f, 0, (size_t)-1); } return -1; } From 856a9bef052889892d67f98239cc2afa5bb64967 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Tue, 25 Oct 2022 16:49:25 -0400 Subject: [PATCH 13/17] clean the definition of RANGE_ERROR --- Modules/_struct.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Modules/_struct.c b/Modules/_struct.c index 69ed3dd291047e..321a34592ac054 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -275,7 +275,7 @@ get_size_t(_structmodulestate *state, PyObject *v, size_t *p) } -#define RANGE_ERROR(state, x, f, flag, mask) return _range_error(state, f, flag) +#define RANGE_ERROR(state, f, flag) return _range_error(state, f, flag) /* Floating point helpers */ @@ -529,7 +529,7 @@ np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; if (get_long(state, v, &x) < 0 || x < -128 || x > 127) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned char)-1); + RANGE_ERROR(state, f, 0); } return -1; } @@ -543,7 +543,7 @@ np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; if (get_long(state, v, &x) < 0 || x < 0 || x > 255) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned char)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -570,7 +570,7 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) short y; if (get_long(state, v, &x) < 0 || x < SHRT_MIN || x > SHRT_MAX) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned short)-1); + RANGE_ERROR(state, f, 0); } return -1; } @@ -586,7 +586,7 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned short y; if (get_long(state, v, &x) < 0 || x < 0 || x > USHRT_MAX) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned short)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -602,13 +602,13 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) int y; if (get_long(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + RANGE_ERROR(state, f, 0); } return -1; } #if (SIZEOF_LONG > SIZEOF_INT) if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX))) - RANGE_ERROR(state, x, f, 0, -1); + RANGE_ERROR(state, f, 0); #endif y = (int)x; memcpy(p, (char *)&y, sizeof y); @@ -622,14 +622,14 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned int y; if (get_ulong(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + RANGE_ERROR(state, f, 1); } return -1; } y = (unsigned int)x; #if (SIZEOF_LONG > SIZEOF_INT) if (x > ((unsigned long)UINT_MAX)) - RANGE_ERROR(state, y, f, 1, -1); + RANGE_ERROR(state, f, 1); #endif memcpy(p, (char *)&y, sizeof y); return 0; @@ -641,7 +641,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; if (get_long(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned long)-1); + RANGE_ERROR(state, f, 0); } return -1; } @@ -655,7 +655,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long x; if (get_ulong(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned long)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -669,7 +669,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t x; if (get_ssize_t(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (size_t)-1); + RANGE_ERROR(state, f, 0); } return -1; } @@ -683,7 +683,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) size_t x; if (get_size_t(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (size_t)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -928,17 +928,17 @@ bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + RANGE_ERROR(state, f, 0); } return -1; } i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(state, x, f, 0, 0xffffL); + RANGE_ERROR(state, f, 0); #if (SIZEOF_LONG != 4) else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(state, x, f, 0, 0xffffffffL); + RANGE_ERROR(state, f, 0); #endif } do { @@ -956,7 +956,7 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -965,7 +965,7 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long maxint = 1; maxint <<= (unsigned long)(i * 8); if (x >= maxint) - RANGE_ERROR(state, x, f, 1, maxint - 1); + RANGE_ERROR(state, f, 1); } do { q[--i] = (unsigned char)(x & 0xffUL); @@ -1188,17 +1188,17 @@ lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 0, (unsigned int)-1); + RANGE_ERROR(state, f, 0); } return -1; } i = f->size; if (i != SIZEOF_LONG) { if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(state, x, f, 0, 0xffffL); + RANGE_ERROR(state, f, 0); #if (SIZEOF_LONG != 4) else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(state, x, f, 0, 0xffffffffL); + RANGE_ERROR(state, f, 0); #endif } do { @@ -1216,7 +1216,7 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { if (!PyErr_ExceptionMatches(state->StructError)) { - RANGE_ERROR(state, x, f, 1, (unsigned int)-1); + RANGE_ERROR(state, f, 1); } return -1; } @@ -1225,7 +1225,7 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long maxint = 1; maxint <<= (unsigned long)(i * 8); if (x >= maxint) - RANGE_ERROR(state, x, f, 1, maxint - 1); + RANGE_ERROR(state, f, 1); } do { *q++ = (unsigned char)(x & 0xffUL); From fbea6874cd3a77562f52146a040c6344412e87c0 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Mon, 28 Nov 2022 21:05:13 -0500 Subject: [PATCH 14/17] handle error propagation correctly --- Lib/test/test_struct.py | 17 ++++++++++++++ Modules/_struct.c | 52 +++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index efe92419ea6d92..2904643752f952 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -756,6 +756,23 @@ def test_error_msg(prefix, int_type, is_unsigned): int_type = 'n' test_error_msg("@", int_type, False) + def test_issue92848_error_propagation(self): + class Div0: + def __index__(self): + 1 / 0 + + def test_error_propagation(fmt_str): + with self.subTest(format_str=fmt_str, exception="ZeroDivisionError"): + with self.assertRaises(ZeroDivisionError): + struct.pack(fmt_str, Div0()) + + for prefix in '@=<>': + for int_type in 'BHILQbhilq': + test_error_propagation(prefix + int_type) + + test_error_propagation('N') + test_error_propagation('n') + class UnpackIteratorTest(unittest.TestCase): """ Tests for iterative unpacking (struct.Struct.iter_unpack). diff --git a/Modules/_struct.c b/Modules/_struct.c index 0169561d7c8e0b..1a3157a3823a60 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -527,12 +527,15 @@ static int np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(state, v, &x) < 0 || x < -128 || x > 127) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (get_long(state, v, &x) < 0) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; } + if (x < -128 || x > 127) { + RANGE_ERROR(state, f, 0); + } *p = (char)x; return 0; } @@ -541,12 +544,15 @@ static int np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; - if (get_long(state, v, &x) < 0 || x < 0 || x > 255) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (get_long(state, v, &x) < 0) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; } + if (x < 0 || x > 255) { + RANGE_ERROR(state, f, 1); + } *(unsigned char *)p = (unsigned char)x; return 0; } @@ -568,12 +574,15 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; short y; - if (get_long(state, v, &x) < 0 || x < SHRT_MIN || x > SHRT_MAX) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (get_long(state, v, &x) < 0) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; } + if (x < SHRT_MIN || x > SHRT_MAX) { + RANGE_ERROR(state, f, 0); + } y = (short)x; memcpy(p, (char *)&y, sizeof y); return 0; @@ -584,12 +593,15 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; unsigned short y; - if (get_long(state, v, &x) < 0 || x < 0 || x > USHRT_MAX) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (get_long(state, v, &x) < 0) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; } + if (x < 0 || x > USHRT_MAX) { + RANGE_ERROR(state, f, 1); + } y = (unsigned short)x; memcpy(p, (char *)&y, sizeof y); return 0; @@ -601,7 +613,7 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) long x; int y; if (get_long(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; @@ -621,7 +633,7 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) unsigned long x; unsigned int y; if (get_ulong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; @@ -640,7 +652,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long x; if (get_long(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; @@ -654,7 +666,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { unsigned long x; if (get_ulong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; @@ -668,7 +680,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { Py_ssize_t x; if (get_ssize_t(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; @@ -682,7 +694,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { size_t x; if (get_size_t(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; @@ -696,7 +708,7 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) { long long x; if (get_longlong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Format(state->StructError, "'%c' format requires %lld <= number <= %lld", f->format, @@ -714,7 +726,7 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f { unsigned long long x; if (get_ulonglong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Format(state->StructError, "'%c' format requires 0 <= number <= %llu", f->format, @@ -927,7 +939,7 @@ bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; @@ -955,7 +967,7 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; @@ -1187,7 +1199,7 @@ lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_long(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 0); } return -1; @@ -1215,7 +1227,7 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f) Py_ssize_t i; unsigned char *q = (unsigned char *)p; if (get_ulong(state, v, &x) < 0) { - if (!PyErr_ExceptionMatches(state->StructError)) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { RANGE_ERROR(state, f, 1); } return -1; From 8296a23ed37e932cf2699a735b24d8cf849a8590 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Mon, 28 Nov 2022 21:05:59 -0500 Subject: [PATCH 15/17] fix wrong issue ids --- Lib/test/test_struct.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 2904643752f952..e1f3845678b53d 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -723,7 +723,7 @@ def test_issue35714(self): struct.calcsize(s) @support.cpython_only - def test_issue92848(self): + def test_issue98248(self): def test_error_msg(prefix, int_type, is_unsigned): fmt_str = prefix + int_type size = struct.calcsize(fmt_str) @@ -756,7 +756,7 @@ def test_error_msg(prefix, int_type, is_unsigned): int_type = 'n' test_error_msg("@", int_type, False) - def test_issue92848_error_propagation(self): + def test_issue98248_error_propagation(self): class Div0: def __index__(self): 1 / 0 From 7b3b283eb085657ddbeb5b7f1a306fb385746c54 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Mon, 28 Nov 2022 21:07:04 -0500 Subject: [PATCH 16/17] minor format change --- Lib/test/test_struct.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index e1f3845678b53d..ac1d2a2cb059bf 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -751,10 +751,10 @@ def test_error_msg(prefix, int_type, is_unsigned): test_error_msg(prefix, int_type, False) int_type = 'N' - test_error_msg("@", int_type, True) + test_error_msg('@', int_type, True) int_type = 'n' - test_error_msg("@", int_type, False) + test_error_msg('@', int_type, False) def test_issue98248_error_propagation(self): class Div0: From 5b6fd702b2a6f4182ab1f648aba3ab4b20f82223 Mon Sep 17 00:00:00 2001 From: Felix Ye Date: Mon, 28 Nov 2022 21:15:04 -0500 Subject: [PATCH 17/17] should only test cpython --- Lib/test/test_struct.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index ac1d2a2cb059bf..6b1f22f66fd157 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -756,6 +756,7 @@ def test_error_msg(prefix, int_type, is_unsigned): int_type = 'n' test_error_msg('@', int_type, False) + @support.cpython_only def test_issue98248_error_propagation(self): class Div0: def __index__(self):