Skip to content

Stack overflow error from recursion with 3.14.0rc1 on MacOS #137573

Description

@cdce8p

Crash report

What happened?

In the pylint / astroid test suite we have a regression test for a common recursion issue on our end. Though the code triggers a deep recursion, so far CPython was still able to resolve it. While getting ready for 3.14, I noticed that a specific test started to crash Python but only on MacOS. Isolated Github action CI runs seem to confirm this, Ubuntu, Windows are completely fine both with 3.13.6 and 3.14.0rc1. However MacOS only passes with 3.13.6 while failing 3.14.0rc1. Noticeable 3.14.0a6 seems to be the last version which reliably still succeeded.

The releases have been downloaded from python.org; used the actions/setup-python action for tests in CI.

To bisect the issue further, I compiled 3.14.0rc1 on my Mac. Strangely though the test now passes, on the same system where the binary from python.org failed previously.

Local tests done with

  • MacOS 14 on M2 Pro
  • Python 3.14.0rc1 (v3.14.0rc1:48f88310044, Jul 22 2025, 13:06:29) [Clang 16.0.0 (clang-1600.0.26.6)] from https://www.python.org/downloads/release/python-3140rc1/ => test fails
  • Python 3.14.0rc1 (tags/v3.14.0rc1:48f88310044, Aug 9 2025, 00:54:21) [Clang 16.0.6 ] compiled manually => test succeeds
CC=/opt/homebrew/opt/llvm@16/bin/clang ./configure --with-openssl=$(brew --prefix openssl@3) --enable-optimizations --with-lto
make -j4 -s

Run the test case

git clone --depth 1 --branch v4.0.0b2 https://github.com/pylint-dev/astroid.git
cd astroid
python -m venv venv
source venv/bin/activate
pip install pytest==8.4.1 .
pytest tests/test_inference.py::test_recursion_on_inference_tip

Output with 3.14.0rc1 from python.org

(venv) MyMacBook-Pro:astroid $ pytest -s tests/test_inference.py::test_recursion_on_inference_tip
============================== test session starts ===================================
platform darwin -- Python 3.14.0rc1, pytest-8.4.1, pluggy-1.6.0
rootdir: /.../astroid
configfile: pyproject.toml
collected 1 item                                                                                                                                                                                                            

tests/test_inference.py Fatal Python error: _Py_CheckRecursiveCall: Unrecoverable stack overflow (used 3953 kB)
Python runtime state: initialized

Current thread 0x00000001dc071ec0 (most recent call first):
  File "/.../astroid/astroid/decorators.py", line 81 in inner
  File "/.../astroid/astroid/nodes/node_classes.py", line 451 in _infer
  ...
  File "/.../astroid/astroid/decorators.py", line 44 in wrapped
  File "/.../astroid/astroid/decorators.py", line 81 in inner
Abort trap: 6

Output with 3.14.0rc1 compiled locally

tests/test_inference.py::test_recursion_on_inference_tip PASSED

--
I'd be grateful about any pointers to things I'm doing "wrong" in my local build that prevent me from reproducing and bisecting the issue.

CPython versions tested on:

3.14

Operating systems tested on:

macOS

Output from running 'python -VV' on the command line:

Python 3.14.0rc1 (v3.14.0rc1:48f88310044, Jul 22 2025, 13:06:29) [Clang 16.0.0 (clang-1600.0.26.6)]

Linked PRs

Activity

  1. added
    type-crashA hard crash of the interpreter, possibly with a core dump
    on Aug 8, 2025
  2. inventshah commented on Aug 10, 2025

    @inventshah
    Contributor

    I think the key change between 3.14.0a6 and 3.14.0b1 is compiling with --enable-experimental-jit=yes-off (#131751 (review)).

    Reproduce locally with: ./configure -C --enable-experimental-jit=yes-off --with-lto=full --enable-optimizations. Note all three flags seem necessary.

    I ran git bisect between bfcbb28 (last commit that touches Tools/jit/_llvm.py) and 1878fe8. The first bad commit is: a5274cd.

    One maybe relevant tidbit the JIT docs mention LLVM 19 as required but the python.org MacOS builds are compiled with clang 16?

  3. inventshah commented on Aug 11, 2025

    @inventshah
    Contributor

    Looks like builtin dunder calls cause the recursion limit to be hit much sooner than it should. Removing __getattribute__ from UninferableBase fixes the test in OP, but breaks other tests. In the other issue for pyclibrary, removing one __str__ call in a dependency also fixes the test reported.

    A minimal repro is

    class Foo:
        def __str__(self):
            return str(self)
    str(Foo())

    This aborts after 144 calls, while redefining str like def str(x): return x.__str__(), reports RecursionError: maximum recursion depth exceeded as expected (and completes the 1000 allowed). 3.13 raises a RecursionError in both cases.

    @hugovk since you asked about a minimal code example in the other issue, and I think these are all related.

  4. AA-Turner commented on Aug 11, 2025

    @AA-Turner
    Member

    Confirming that on Windows the example fails properly with a RecursionError:

    Python 3.14.0rc1 (tags/v3.14.0rc1:48f8831, Jul 22 2025, 17:09:57) [MSC v.1944 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> class Foo:
    ...     def __str__(self):
    ...         return str(self)
    ...
    >>> str(Foo())
    Traceback (most recent call last):
      File "<python-input-1>", line 1, in <module>
        str(Foo())
        ~~~^^^^^^^
      File "<python-input-0>", line 3, in __str__
        return str(self)
      File "<python-input-0>", line 3, in __str__
        return str(self)
      File "<python-input-0>", line 3, in __str__
        return str(self)
      [Previous line repeated 991 more times]
    RecursionError: maximum recursion depth exceeded
  5. AA-Turner commented on Aug 11, 2025

    @AA-Turner
    Member
  6. inventshah commented on Aug 11, 2025

    @inventshah
    Contributor

    I guess the problem isn't exactly in recursion, but rather something about the stack use of dunder calls. I had also set up a chain of 144 nested classes that subsequently call a child's str (something that should not error, and is probably more akin to whats happening in the failed tests). That hits RecursionError: Stack overflow, while one fewer nested class works.

    Click to expand class generator
      template = """
      class A{idx}:
          x{idx} = A{idx2}()
          def __str__(self):
              return str(self.x{idx})
      """
      
      with open("repro.py", "w") as f:
          f.write(
              """
      class A0:
          def __str__(self):
              return "here"
      """
          )
          for idx in range(1, 143):
              f.write(template.format(idx=idx, idx2=idx - 1))
      
          f.write(f"print(A{idx}())")
    
  7. encukou commented on Aug 11, 2025

    @encukou
    Member

    #131543 looks similar.

  8. inventshah commented on Aug 11, 2025

    @inventshah
    Contributor

    Looks like in 3.14.0b1 we can have a chain of 376 classes, while in the 3.14.0rc1 only 144. FWIW, there is this comment about lto in configure so maybe --with-lto=full is broken (when I compile with thin it seems to be fine...)

    cpython/configure

    Lines 8410 to 8413 in 3626928

    # Intentionally not forcing Py_LTO='true' here. Too many toolchains do not
    # compile working code using it and both test_distutils and test_gdb are
    # broken when you do manage to get a toolchain that works with it. People
    # who want LTO need to use --with-lto themselves.

    Also, the main testsuite has failures, like test_isinstance.TestIsInstanceIsSubclass.test_infinite_cycle_in_bases, so this should be catchable via CI.

  9. inventshah commented on Aug 11, 2025

    @inventshah
    Contributor

    Ran another git bisect with the infinite recursion repro, and ac3c439 is the first bad commit (starting from 3.14.0a05), which looks more relevant than the other commit. Note I still need --enable-experimental-jit=yes-off, which the alphas aren't compiled with, so I think there may be another issue further back or toolchain bug.

  10. 23 remaining items

  11. added a commit that references this issue on Sep 9, 2025
  12. added a commit that references this issue on Sep 23, 2025
  13. cdce8p commented on Sep 24, 2025

    @cdce8p
    ContributorAuthor

    Is there anything left here? I believe all has been resolved and this issue could be closed.

  14. AA-Turner commented on Sep 24, 2025

    @AA-Turner
    Member

    The test was merged, but has not been backported. cc @encukou if he wants to do so.

  15. added
    pendingThe issue will be closed if no feedback is provided
    on Sep 24, 2025
  16. added a commit that references this issue on Sep 24, 2025
  17. encukou commented on Sep 24, 2025

    @encukou
    Member

    Yes, this makes sense for 3.14.1. #139295 is the backport

  18. added a commit that references this issue on Oct 8, 2025
  19. hugovk commented on Oct 10, 2025

    @hugovk
    Member

    The backport has been merged.

    (A downside of keeping issues open to track backports is merging the backport and forgetting the issue :)

  20. added 2 commits that reference this issue on Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.14bugs and security fixesOS-macpendingThe issue will be closed if no feedback is providedtype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions