]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] GH-137573: Add test to check that the margin used for overflow protection...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Wed, 8 Oct 2025 12:44:16 +0000 (14:44 +0200)
committerGitHub <noreply@github.com>
Wed, 8 Oct 2025 12:44:16 +0000 (14:44 +0200)
(cherry picked from commit 16eae6d90d49ef036b010777ceffd130cfa96126)

Co-authored-by: Mark Shannon <mark@hotpy.org>
Co-authored-by: Petr Viktorin <encukou@gmail.com>
Lib/test/test_call.py
Modules/_testinternalcapi.c

index 2c28f106ec7cb68552fece184bb3cd50522e0629..fcbef1ae86bed543eed6f74075d6d4f59e407086 100644 (file)
@@ -12,6 +12,10 @@ try:
     import _testlimitedcapi
 except ImportError:
     _testlimitedcapi = None
+try:
+    import _testinternalcapi
+except ImportError:
+    _testinternalcapi = None
 import struct
 import collections
 import itertools
@@ -1037,6 +1041,18 @@ class TestErrorMessagesSuggestions(unittest.TestCase):
 @cpython_only
 class TestRecursion(unittest.TestCase):
 
+    def test_margin_is_sufficient(self):
+
+        def get_sp():
+            return _testinternalcapi.get_stack_pointer()
+
+        this_sp = _testinternalcapi.get_stack_pointer()
+        lower_sp = _testcapi.pyobject_vectorcall(get_sp, (), ())
+        self.assertLess(lower_sp, this_sp)
+        # Add an (arbitrary) extra 20% for safety
+        safe_margin = (this_sp - lower_sp) * 6 / 5
+        self.assertLess(safe_margin, _testinternalcapi.get_stack_margin())
+
     @skip_on_s390x
     @unittest.skipIf(is_wasi and Py_DEBUG, "requires deep stack")
     @skip_if_sanitizer("requires deep stack", thread=True)
index f84cf1a4263a2dde06febad23672af7202cb7499..afb72d3df832365f8cdd8f3411e7fea8fb734824 100644 (file)
@@ -125,6 +125,18 @@ get_c_recursion_remaining(PyObject *self, PyObject *Py_UNUSED(args))
     return PyLong_FromLong(remaining);
 }
 
+static PyObject*
+get_stack_pointer(PyObject *self, PyObject *Py_UNUSED(args))
+{
+    uintptr_t here_addr = _Py_get_machine_stack_pointer();
+    return PyLong_FromSize_t(here_addr);
+}
+
+static PyObject*
+get_stack_margin(PyObject *self, PyObject *Py_UNUSED(args))
+{
+    return PyLong_FromSize_t(_PyOS_STACK_MARGIN_BYTES);
+}
 
 static PyObject*
 test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
@@ -2381,6 +2393,8 @@ static PyMethodDef module_functions[] = {
     {"get_configs", get_configs, METH_NOARGS},
     {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
     {"get_c_recursion_remaining", get_c_recursion_remaining, METH_NOARGS},
+    {"get_stack_pointer", get_stack_pointer, METH_NOARGS},
+    {"get_stack_margin", get_stack_margin, METH_NOARGS},
     {"test_bswap", test_bswap, METH_NOARGS},
     {"test_popcount", test_popcount, METH_NOARGS},
     {"test_bit_length", test_bit_length, METH_NOARGS},