https://github.com/python/cpython/commit/35a7a6767e9fbda4d4462afe81a3c3c6dca7ef33
commit: 35a7a6767e9fbda4d4462afe81a3c3c6dca7ef33
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: gpshead <[email protected]>
date: 2026-02-24T01:18:32Z
summary:

[3.14] `_struct.c`: Fix UB from integer overflow in `prepare_s` (GH-145158) 
(#145162)

`_struct.c`: Fix UB from integer overflow in `prepare_s` (GH-145158)

Avoid possible undefined behaviour from signed overflow in `struct` module

As discovered via oss-fuzz.
(cherry picked from commit fd0400585eb957c7d10812d87a8cb9e1f3c72519)

Co-authored-by: Stan Ulbrych <[email protected]>

files:
A Misc/NEWS.d/next/Library/2026-02-23-20-52-55.gh-issue-145158.vWJtxI.rst
M Lib/test/test_struct.py
M Modules/_struct.c

diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 59133e24e649fa..2b8d19ac966444 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -552,6 +552,9 @@ def test_count_overflow(self):
         hugecount2 = '{}b{}H'.format(sys.maxsize//2, sys.maxsize//2)
         self.assertRaises(struct.error, struct.calcsize, hugecount2)
 
+        hugecount3 = '{}i{}q'.format(sys.maxsize // 4, sys.maxsize // 8)
+        self.assertRaises(struct.error, struct.calcsize, hugecount3)
+
     def test_trailing_counter(self):
         store = array.array('b', b' '*100)
 
diff --git 
a/Misc/NEWS.d/next/Library/2026-02-23-20-52-55.gh-issue-145158.vWJtxI.rst 
b/Misc/NEWS.d/next/Library/2026-02-23-20-52-55.gh-issue-145158.vWJtxI.rst
new file mode 100644
index 00000000000000..60a5e4ad1f0ca4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-02-23-20-52-55.gh-issue-145158.vWJtxI.rst
@@ -0,0 +1,2 @@
+Avoid undefined behaviour from signed integer overflow when parsing format
+strings in the :mod:`struct` module.
diff --git a/Modules/_struct.c b/Modules/_struct.c
index 87014a4a1e37ad..61d3ab0d7a474c 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1678,7 +1678,15 @@ prepare_s(PyStructObject *self)
             case 's': _Py_FALLTHROUGH;
             case 'p': len++; ncodes++; break;
             case 'x': break;
-            default: len += num; if (num) ncodes++; break;
+            default:
+                if (num > PY_SSIZE_T_MAX - len) {
+                    goto overflow;
+                }
+                len += num;
+                if (num) {
+                    ncodes++;
+                }
+                break;
         }
 
         itemsize = e->size;

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to