]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] `_struct.c`: Fix UB from integer overflow in `prepare_s` (GH-145158) (#145162)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 24 Feb 2026 01:18:32 +0000 (02:18 +0100)
committerGitHub <noreply@github.com>
Tue, 24 Feb 2026 01:18:32 +0000 (01:18 +0000)
`_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 <89152624+StanFromIreland@users.noreply.github.com>
Lib/test/test_struct.py
Misc/NEWS.d/next/Library/2026-02-23-20-52-55.gh-issue-145158.vWJtxI.rst [new file with mode: 0644]
Modules/_struct.c

index 59133e24e649fa5336e6122f5600bdd0895fa2ab..2b8d19ac966444ea0b24e14fb31f075085f403b6 100644 (file)
@@ -552,6 +552,9 @@ class StructTest(ComplexesAreIdenticalMixin, unittest.TestCase):
         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 (file)
index 0000000..60a5e4a
--- /dev/null
@@ -0,0 +1,2 @@
+Avoid undefined behaviour from signed integer overflow when parsing format
+strings in the :mod:`struct` module.
index 87014a4a1e37adb5597063f002509518028ff9bd..61d3ab0d7a474c516f749c5006f585d9dd20870e 100644 (file)
@@ -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;