Skip to content

Commit 0b447ba

Browse files
skirpichevvstinner
andauthored
gh-156865: struct.pack() check for overflows for Zf type (#156868)
Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 5ec9283 commit 0b447ba

3 files changed

Lines changed: 38 additions & 7 deletions

File tree

‎Lib/test/test_struct.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,20 @@ def test_705836(self):
424424
self.assertRaises(OverflowError, struct.pack, "<e", big)
425425
self.assertRaises(OverflowError, struct.pack, "e", big)
426426

427+
def test_float_complex_overflow(self):
428+
for value in (
429+
1e300 + 0.5j, # big real
430+
1.5 + 1e300j, # big imag
431+
):
432+
for format in (">Zf", "<Zf", "Zf"):
433+
with self.subTest(value=value, format=format):
434+
self.assertRaises(OverflowError, struct.pack, format, value)
435+
436+
ba = bytearray(8)
437+
with self.assertRaises(OverflowError):
438+
struct.Struct(format).pack_into(ba, 0, value)
439+
self.assertEqual(ba, bytearray(8))
440+
427441
def test_1530559(self):
428442
for code, byteorder in iter_integer_formats():
429443
format = byteorder + code
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Raise :exc:`OverflowError`'s for native ``'Zf'`` format in :func:`struct.pack`,
2+
like for ``'f'`` format. Previously overflows in the :c:expr:`float complex`
3+
type were silent. Patch by Sergey B Kirpichev.

‎Modules/_struct.c‎

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -790,14 +790,19 @@ np_float_complex(_structmodulestate *state, char *p, PyObject *v,
790790
const formatdef *f)
791791
{
792792
Py_complex c = PyComplex_AsCComplex(v);
793-
float x[2] = {(float)c.real, (float)c.imag};
793+
char tmp[8];
794794

795795
if (c.real == -1 && PyErr_Occurred()) {
796796
PyErr_SetString(state->StructError,
797797
"required argument is not a complex");
798798
return -1;
799799
}
800-
memcpy(p, &x, sizeof(x));
800+
if (PyFloat_Pack4(c.real, tmp, PY_LITTLE_ENDIAN)
801+
|| PyFloat_Pack4(c.imag, tmp + 4, PY_LITTLE_ENDIAN))
802+
{
803+
return -1;
804+
}
805+
memcpy(p, tmp, 8);
801806
return 0;
802807
}
803808

@@ -1132,15 +1137,20 @@ static int
11321137
bp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
11331138
{
11341139
Py_complex x = PyComplex_AsCComplex(v);
1140+
char tmp[8];
1141+
11351142
if (x.real == -1 && PyErr_Occurred()) {
11361143
PyErr_SetString(state->StructError,
11371144
"required argument is not a complex");
11381145
return -1;
11391146
}
1140-
if (PyFloat_Pack4(x.real, p, 0)) {
1147+
if (PyFloat_Pack4(x.real, tmp, 0)
1148+
|| PyFloat_Pack4(x.imag, tmp + 4, 0))
1149+
{
11411150
return -1;
11421151
}
1143-
return PyFloat_Pack4(x.imag, p + 4, 0);
1152+
memcpy(p, tmp, 8);
1153+
return 0;
11441154
}
11451155

11461156
static int
@@ -1458,16 +1468,20 @@ static int
14581468
lp_float_complex(_structmodulestate *state, char *p, PyObject *v, const formatdef *f)
14591469
{
14601470
Py_complex x = PyComplex_AsCComplex(v);
1471+
char tmp[8];
1472+
14611473
if (x.real == -1 && PyErr_Occurred()) {
14621474
PyErr_SetString(state->StructError,
14631475
"required argument is not a complex");
14641476
return -1;
14651477
}
1466-
if (PyFloat_Pack4(x.real, p, 1)) {
1478+
if (PyFloat_Pack4(x.real, tmp, 1)
1479+
|| PyFloat_Pack4(x.imag, tmp + 4, 1))
1480+
{
14671481
return -1;
14681482
}
1469-
return PyFloat_Pack4(x.imag, p + 4, 1);
1470-
1483+
memcpy(p, tmp, 8);
1484+
return 0;
14711485
}
14721486

14731487
static int

0 commit comments

Comments
 (0)