summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Schubert <brianm.schubert@gmail.com>2024-09-20 10:08:59 (GMT)
committerGitHub <noreply@github.com>2024-09-20 10:08:59 (GMT)
commit63f196090f90cbfe5f698824655f74dea5cb2b29 (patch)
tree53673a94db1e9a94bea99f0cc6af3611d910d5a0
parentbaa3550bc3a119f41cc4eaed5373f9d695208e8e (diff)
downloadcpython-63f196090f90cbfe5f698824655f74dea5cb2b29.zip
cpython-63f196090f90cbfe5f698824655f74dea5cb2b29.tar.gz
cpython-63f196090f90cbfe5f698824655f74dea5cb2b29.tar.bz2
gh-124248: Fix crash in struct when processing 0p fields (#124251)
-rw-r--r--Lib/test/test_struct.py9
-rw-r--r--Misc/ACKS1
-rw-r--r--Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst2
-rw-r--r--Modules/_struct.c19
4 files changed, 27 insertions, 4 deletions
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 5508cc3..bdbf880 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -96,6 +96,13 @@ class StructTest(unittest.TestCase):
('10s', b'helloworld', b'helloworld', b'helloworld', 0),
('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1),
('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1),
+ ('0p', b'helloworld', b'', b'', 1),
+ ('1p', b'helloworld', b'\x00', b'\x00', 1),
+ ('2p', b'helloworld', b'\x01h', b'\x01h', 1),
+ ('10p', b'helloworld', b'\x09helloworl', b'\x09helloworl', 1),
+ ('11p', b'helloworld', b'\x0Ahelloworld', b'\x0Ahelloworld', 0),
+ ('12p', b'helloworld', b'\x0Ahelloworld\0', b'\x0Ahelloworld\0', 1),
+ ('20p', b'helloworld', b'\x0Ahelloworld'+9*b'\0', b'\x0Ahelloworld'+9*b'\0', 1),
('b', 7, b'\7', b'\7', 0),
('b', -7, b'\371', b'\371', 0),
('B', 7, b'\7', b'\7', 0),
@@ -339,6 +346,7 @@ class StructTest(unittest.TestCase):
def test_p_code(self):
# Test p ("Pascal string") code.
for code, input, expected, expectedback in [
+ ('0p', b'abc', b'', b''),
('p', b'abc', b'\x00', b''),
('1p', b'abc', b'\x00', b''),
('2p', b'abc', b'\x01a', b'a'),
@@ -580,6 +588,7 @@ class StructTest(unittest.TestCase):
self.check_sizeof('187s', 1)
self.check_sizeof('20p', 1)
self.check_sizeof('0s', 1)
+ self.check_sizeof('0p', 1)
self.check_sizeof('0c', 0)
def test_boundary_error_message(self):
diff --git a/Misc/ACKS b/Misc/ACKS
index b031eb7..2db17ad 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1653,6 +1653,7 @@ Scott Schram
Robin Schreiber
Chad J. Schroeder
Simon-Martin Schroeder
+Brian Schubert
Christian Schubert
Sam Schulenburg
Andreas Schwab
diff --git a/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst b/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst
new file mode 100644
index 0000000..1bd333f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-09-19-11-47-39.gh-issue-124248.g7rufd.rst
@@ -0,0 +1,2 @@
+Fixed potential crash when using :mod:`struct` to process zero-width
+'Pascal string' fields (``0p``).
diff --git a/Modules/_struct.c b/Modules/_struct.c
index f744193..2ae5060 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1669,9 +1669,16 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom,
if (e->format == 's') {
v = PyBytes_FromStringAndSize(res, code->size);
} else if (e->format == 'p') {
- Py_ssize_t n = *(unsigned char*)res;
- if (n >= code->size)
- n = code->size - 1;
+ Py_ssize_t n;
+ if (code->size == 0) {
+ n = 0;
+ }
+ else {
+ n = *(unsigned char*)res;
+ if (n >= code->size) {
+ n = code->size - 1;
+ }
+ }
v = PyBytes_FromStringAndSize(res + 1, n);
} else {
v = e->unpack(state, res, e);
@@ -1982,8 +1989,12 @@ s_pack_internal(PyStructObject *soself, PyObject *const *args, int offset,
n = PyByteArray_GET_SIZE(v);
p = PyByteArray_AS_STRING(v);
}
- if (n > (code->size - 1))
+ if (code->size == 0) {
+ n = 0;
+ }
+ else if (n > (code->size - 1)) {
n = code->size - 1;
+ }
if (n > 0)
memcpy(res + 1, p, n);
if (n > 255)