From 560adb01f97015a6778568e057aa3eeaace3b5f4 Mon Sep 17 00:00:00 2001
From: "Miss Islington (bot)"
 <31488909+miss-islington@users.noreply.github.com>
Date: Fri, 16 Jun 2023 11:29:55 -0700
Subject: [3.12] GH-105840: Fix assertion failures when specializing calls with
 too many __defaults__ (GH-105863)

GH-105840: Fix assertion failures when specializing calls with too many __defaults__ (GH-105847)
(cherry picked from commit 2beab5bdef5fa2a00a59371e6137f769586b7404)

Co-authored-by: Brandt Bucher <brandtbucher@microsoft.com>
---
 Lib/test/test_opcache.py                           | 29 ++++++++++++++++++++++
 .../2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst |  2 ++
 Python/specialize.c                                |  4 +--
 3 files changed, 33 insertions(+), 2 deletions(-)
 create mode 100644 Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst

diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index 57fed5d..5281eb7 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -452,6 +452,35 @@ class TestLoadMethodCache(unittest.TestCase):
             self.assertFalse(f())
 
 
+class TestCallCache(unittest.TestCase):
+    def test_too_many_defaults_0(self):
+        def f():
+            pass
+
+        f.__defaults__ = (None,)
+        for _ in range(1025):
+            f()
+
+    def test_too_many_defaults_1(self):
+        def f(x):
+            pass
+
+        f.__defaults__ = (None, None)
+        for _ in range(1025):
+            f(None)
+            f()
+
+    def test_too_many_defaults_2(self):
+        def f(x, y):
+            pass
+
+        f.__defaults__ = (None, None, None)
+        for _ in range(1025):
+            f(None, None)
+            f(None)
+            f()
+
+
 if __name__ == "__main__":
     import unittest
     unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst
new file mode 100644
index 0000000..5225031
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-15-22-11-43.gh-issue-105840.Fum_g_.rst	
@@ -0,0 +1,2 @@
+Fix possible crashes when specializing function calls with too many
+``__defaults__``.
diff --git a/Python/specialize.c b/Python/specialize.c
index f168491..63b4446 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -1666,9 +1666,9 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs,
     }
     int argcount = code->co_argcount;
     int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
-    assert(defcount <= argcount);
     int min_args = argcount-defcount;
-    if (nargs > argcount || nargs < min_args) {
+    // GH-105840: min_args is negative when somebody sets too many __defaults__!
+    if (min_args < 0 || nargs > argcount || nargs < min_args) {
         SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
         return -1;
     }
-- 
cgit v0.12