Skip to content

Commit 439a9dd

Browse files
Commit
1 parent 79f7c67 commit 439a9dd

File tree

4 files changed

+50
-36
lines changed

4 files changed

+50
-36
lines changed

Doc/library/struct.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ The module defines the following exception and functions:
5555
Exception raised on various occasions; argument is a string describing what
5656
is wrong.
5757

58+
.. versionchanged::
59+
Out of range errors are more descriptive specifying which argument resulted
60+
in the exception.
61+
5862

5963
.. function:: pack(format, v1, v2, ...)
6064

Lib/test/test_struct.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ def test_error_msg(prefix, int_type, is_unsigned):
742742
else:
743743
max_ = 2 ** (size * 8 - 1) - 1
744744
min_ = -2 ** (size * 8 - 1)
745-
error_msg = f"'{int_type}' format requires {min_} <= number <= {max_}"
745+
error_msg = f"'{int_type}' format requires {min_} <= arg 1 <= {max_}"
746746
for number in [int(-1e50), min_ - 1, max_ + 1, int(1e50)]:
747747
with self.subTest(format_str=fmt_str, number=number):
748748
with self.assertRaisesRegex(struct.error, error_msg):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:func:`struct.pack` raises more informative errors when an argument is out of range.

Modules/_struct.c

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ typedef struct {
2727
PyObject *PyStructType;
2828
PyObject *unpackiter_type;
2929
PyObject *StructError;
30+
Py_ssize_t current_arg;
3031
} _structmodulestate;
3132

3233
static inline _structmodulestate*
@@ -290,7 +291,7 @@ get_size_t(_structmodulestate *state, PyObject *v, size_t *p)
290291
}
291292

292293

293-
#define RANGE_ERROR(state, f, flag) return _range_error(state, f, flag)
294+
#define RANGE_ERROR(state, f, flag, loc) return _range_error(state, f, flag, loc)
294295

295296

296297
/* Floating-point helpers */
@@ -347,7 +348,7 @@ unpack_double(const char *p, /* start of 8-byte string */
347348

348349
/* Helper to format the range error exceptions */
349350
static int
350-
_range_error(_structmodulestate *state, const formatdef *f, int is_unsigned)
351+
_range_error(_structmodulestate *state, const formatdef *f, int is_unsigned, Py_ssize_t loc)
351352
{
352353
/* ulargest is the largest unsigned value with f->size bytes.
353354
* Note that the simpler:
@@ -361,15 +362,17 @@ _range_error(_structmodulestate *state, const formatdef *f, int is_unsigned)
361362
assert(f->size >= 1 && f->size <= SIZEOF_SIZE_T);
362363
if (is_unsigned)
363364
PyErr_Format(state->StructError,
364-
"'%c' format requires 0 <= number <= %zu",
365+
"'%c' format requires 0 <= arg %zd <= %zu",
365366
f->format,
367+
loc,
366368
ulargest);
367369
else {
368370
const Py_ssize_t largest = (Py_ssize_t)(ulargest >> 1);
369371
PyErr_Format(state->StructError,
370-
"'%c' format requires %zd <= number <= %zd",
372+
"'%c' format requires %zd <= arg %zd <= %zd",
371373
f->format,
372374
~ largest,
375+
loc,
373376
largest);
374377
}
375378

@@ -563,12 +566,12 @@ np_byte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
563566
long x;
564567
if (get_long(state, v, &x) < 0) {
565568
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
566-
RANGE_ERROR(state, f, 0);
569+
RANGE_ERROR(state, f, 0, state->current_arg);
567570
}
568571
return -1;
569572
}
570573
if (x < -128 || x > 127) {
571-
RANGE_ERROR(state, f, 0);
574+
RANGE_ERROR(state, f, 0, state->current_arg);
572575
}
573576
*p = (char)x;
574577
return 0;
@@ -580,12 +583,12 @@ np_ubyte(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
580583
long x;
581584
if (get_long(state, v, &x) < 0) {
582585
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
583-
RANGE_ERROR(state, f, 1);
586+
RANGE_ERROR(state, f, 1, state->current_arg);
584587
}
585588
return -1;
586589
}
587590
if (x < 0 || x > 255) {
588-
RANGE_ERROR(state, f, 1);
591+
RANGE_ERROR(state, f, 1, state->current_arg);
589592
}
590593
*(unsigned char *)p = (unsigned char)x;
591594
return 0;
@@ -610,12 +613,12 @@ np_short(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
610613
short y;
611614
if (get_long(state, v, &x) < 0) {
612615
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
613-
RANGE_ERROR(state, f, 0);
616+
RANGE_ERROR(state, f, 0, state->current_arg);
614617
}
615618
return -1;
616619
}
617620
if (x < SHRT_MIN || x > SHRT_MAX) {
618-
RANGE_ERROR(state, f, 0);
621+
RANGE_ERROR(state, f, 0, state->current_arg);
619622
}
620623
y = (short)x;
621624
memcpy(p, &y, sizeof y);
@@ -629,12 +632,12 @@ np_ushort(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
629632
unsigned short y;
630633
if (get_long(state, v, &x) < 0) {
631634
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
632-
RANGE_ERROR(state, f, 1);
635+
RANGE_ERROR(state, f, 1, state->current_arg);
633636
}
634637
return -1;
635638
}
636639
if (x < 0 || x > USHRT_MAX) {
637-
RANGE_ERROR(state, f, 1);
640+
RANGE_ERROR(state, f, 1, state->current_arg);
638641
}
639642
y = (unsigned short)x;
640643
memcpy(p, &y, sizeof y);
@@ -648,13 +651,13 @@ np_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
648651
int y;
649652
if (get_long(state, v, &x) < 0) {
650653
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
651-
RANGE_ERROR(state, f, 0);
654+
RANGE_ERROR(state, f, 0, state->current_arg);
652655
}
653656
return -1;
654657
}
655658
#if (SIZEOF_LONG > SIZEOF_INT)
656659
if ((x < ((long)INT_MIN)) || (x > ((long)INT_MAX)))
657-
RANGE_ERROR(state, f, 0);
660+
RANGE_ERROR(state, f, 0, state->current_arg);
658661
#endif
659662
y = (int)x;
660663
memcpy(p, &y, sizeof y);
@@ -668,14 +671,14 @@ np_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
668671
unsigned int y;
669672
if (get_ulong(state, v, &x) < 0) {
670673
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
671-
RANGE_ERROR(state, f, 1);
674+
RANGE_ERROR(state, f, 1, state->current_arg);
672675
}
673676
return -1;
674677
}
675678
y = (unsigned int)x;
676679
#if (SIZEOF_LONG > SIZEOF_INT)
677680
if (x > ((unsigned long)UINT_MAX))
678-
RANGE_ERROR(state, f, 1);
681+
RANGE_ERROR(state, f, 1, state->current_arg);
679682
#endif
680683
memcpy(p, &y, sizeof y);
681684
return 0;
@@ -687,7 +690,7 @@ np_long(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
687690
long x;
688691
if (get_long(state, v, &x) < 0) {
689692
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
690-
RANGE_ERROR(state, f, 0);
693+
RANGE_ERROR(state, f, 0, state->current_arg);
691694
}
692695
return -1;
693696
}
@@ -701,7 +704,7 @@ np_ulong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
701704
unsigned long x;
702705
if (get_ulong(state, v, &x) < 0) {
703706
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
704-
RANGE_ERROR(state, f, 1);
707+
RANGE_ERROR(state, f, 1, state->current_arg);
705708
}
706709
return -1;
707710
}
@@ -715,7 +718,7 @@ np_ssize_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
715718
Py_ssize_t x;
716719
if (get_ssize_t(state, v, &x) < 0) {
717720
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
718-
RANGE_ERROR(state, f, 0);
721+
RANGE_ERROR(state, f, 0, state->current_arg);
719722
}
720723
return -1;
721724
}
@@ -729,7 +732,7 @@ np_size_t(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
729732
size_t x;
730733
if (get_size_t(state, v, &x) < 0) {
731734
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
732-
RANGE_ERROR(state, f, 1);
735+
RANGE_ERROR(state, f, 1, state->current_arg);
733736
}
734737
return -1;
735738
}
@@ -744,9 +747,10 @@ np_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
744747
if (get_longlong(state, v, &x) < 0) {
745748
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
746749
PyErr_Format(state->StructError,
747-
"'%c' format requires %lld <= number <= %lld",
750+
"'%c' format requires %lld <= arg %zd <= %lld",
748751
f->format,
749752
LLONG_MIN,
753+
state->current_arg,
750754
LLONG_MAX);
751755
}
752756
return -1;
@@ -762,8 +766,9 @@ np_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
762766
if (get_ulonglong(state, v, &x) < 0) {
763767
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
764768
PyErr_Format(state->StructError,
765-
"'%c' format requires 0 <= number <= %llu",
769+
"'%c' format requires 0 <= arg %zd <= %llu",
766770
f->format,
771+
state->current_arg,
767772
ULLONG_MAX);
768773
}
769774
return -1;
@@ -1065,17 +1070,17 @@ bp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
10651070
unsigned char *q = (unsigned char *)p;
10661071
if (get_long(state, v, &x) < 0) {
10671072
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1068-
RANGE_ERROR(state, f, 0);
1073+
RANGE_ERROR(state, f, 0, state->current_arg);
10691074
}
10701075
return -1;
10711076
}
10721077
i = f->size;
10731078
if (i != SIZEOF_LONG) {
10741079
if ((i == 2) && (x < -32768 || x > 32767))
1075-
RANGE_ERROR(state, f, 0);
1080+
RANGE_ERROR(state, f, 0, state->current_arg);
10761081
#if (SIZEOF_LONG != 4)
10771082
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
1078-
RANGE_ERROR(state, f, 0);
1083+
RANGE_ERROR(state, f, 0, state->current_arg);
10791084
#endif
10801085
}
10811086
do {
@@ -1093,7 +1098,7 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
10931098
unsigned char *q = (unsigned char *)p;
10941099
if (get_ulong(state, v, &x) < 0) {
10951100
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1096-
RANGE_ERROR(state, f, 1);
1101+
RANGE_ERROR(state, f, 1, state->current_arg);
10971102
}
10981103
return -1;
10991104
}
@@ -1102,7 +1107,7 @@ bp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
11021107
unsigned long maxint = 1;
11031108
maxint <<= (unsigned long)(i * 8);
11041109
if (x >= maxint)
1105-
RANGE_ERROR(state, f, 1);
1110+
RANGE_ERROR(state, f, 1, state->current_arg);
11061111
}
11071112
do {
11081113
q[--i] = (unsigned char)(x & 0xffUL);
@@ -1127,9 +1132,10 @@ bp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
11271132
Py_DECREF(v);
11281133
if (res < 0) {
11291134
PyErr_Format(state->StructError,
1130-
"'%c' format requires %lld <= number <= %lld",
1135+
"'%c' format requires %lld <= arg %zd <= %lld",
11311136
f->format,
11321137
LLONG_MIN,
1138+
state->current_arg,
11331139
LLONG_MAX);
11341140
return -1;
11351141
}
@@ -1152,8 +1158,9 @@ bp_ulonglong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f
11521158
Py_DECREF(v);
11531159
if (res < 0) {
11541160
PyErr_Format(state->StructError,
1155-
"'%c' format requires 0 <= number <= %llu",
1161+
"'%c' format requires 0 <= arg %zd <= %llu",
11561162
f->format,
1163+
state->current_arg,
11571164
ULLONG_MAX);
11581165
return -1;
11591166
}
@@ -1398,17 +1405,17 @@ lp_int(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
13981405
unsigned char *q = (unsigned char *)p;
13991406
if (get_long(state, v, &x) < 0) {
14001407
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1401-
RANGE_ERROR(state, f, 0);
1408+
RANGE_ERROR(state, f, 0, state->current_arg);
14021409
}
14031410
return -1;
14041411
}
14051412
i = f->size;
14061413
if (i != SIZEOF_LONG) {
14071414
if ((i == 2) && (x < -32768 || x > 32767))
1408-
RANGE_ERROR(state, f, 0);
1415+
RANGE_ERROR(state, f, 0, state->current_arg);
14091416
#if (SIZEOF_LONG != 4)
14101417
else if ((i == 4) && (x < -2147483648L || x > 2147483647L))
1411-
RANGE_ERROR(state, f, 0);
1418+
RANGE_ERROR(state, f, 0, state->current_arg);
14121419
#endif
14131420
}
14141421
do {
@@ -1426,7 +1433,7 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
14261433
unsigned char *q = (unsigned char *)p;
14271434
if (get_ulong(state, v, &x) < 0) {
14281435
if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
1429-
RANGE_ERROR(state, f, 1);
1436+
RANGE_ERROR(state, f, 1, state->current_arg);
14301437
}
14311438
return -1;
14321439
}
@@ -1435,7 +1442,7 @@ lp_uint(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
14351442
unsigned long maxint = 1;
14361443
maxint <<= (unsigned long)(i * 8);
14371444
if (x >= maxint)
1438-
RANGE_ERROR(state, f, 1);
1445+
RANGE_ERROR(state, f, 1, state->current_arg);
14391446
}
14401447
do {
14411448
*q++ = (unsigned char)(x & 0xffUL);
@@ -1460,9 +1467,10 @@ lp_longlong(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
14601467
Py_DECREF(v);
14611468
if (res < 0) {
14621469
PyErr_Format(state->StructError,
1463-
"'%c' format requires %lld <= number <= %lld",
1470+
"'%c' format requires %lld <= arg %zd <= %lld",
14641471
f->format,
14651472
LLONG_MIN,
1473+
state->current_arg,
14661474
LLONG_MAX);
14671475
return -1;
14681476
}
@@ -2193,6 +2201,7 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset,
21932201
char *res = buf + code->offset;
21942202
Py_ssize_t j = code->repeat;
21952203
while (j--) {
2204+
state->current_arg = i + 1;
21962205
PyObject *v = args[i++];
21972206
if (e->format == 's') {
21982207
Py_ssize_t n;

0 commit comments

Comments
 (0)