You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test_json case test_highly_nested_objects_decoding fails under PGO on Clang 20 #140125
Building 3.15.0a1 on aarch64 macOS with Clang 20 in python-build-standalone failed during the PGO test run in test_highly_nested_objects_decoding:
cpython-3.15> FAIL: test_highly_nested_objects_decoding (test.test_json.test_recursion.TestCRecursion.test_highly_nested_objects_decoding)
cpython-3.15> ----------------------------------------------------------------------
cpython-3.15> Traceback (most recent call last):
cpython-3.15> File "/private/var/folders/6p/k5sd5z7j31b31pq4lhn0l8d80000gn/T/tmp7fxaapg7/Python-3.15.0a1/Lib/test/test_json/test_recursion.py", line 77, in test_highly_nested_objects_decoding
cpython-3.15> with self.assertRaises(RecursionError):
cpython-3.15> ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
cpython-3.15> AssertionError: RecursionError not raised
This failure is specific to macOS, and also occurs on x86-64. I haven't reproduced it outside of python-build-standalone yet. Jump to #140125 (comment) for the root cause.
Just to be clear, my failure occurred while running the profile task, e.g., here, rather than during the test run after a successful build — so I'd expect it to fail during make.
We're specifically using clang 20.1.4 over in python-build-standalone. I tried to reproduce this on HEAD (2ca3c85) on my macOS machine with LLVM clang 20.1.3 from homebrew and could not — the build succeeded. I suspect there may be an interaction with another facet of our build system.
I've opened astral-sh/python-build-standalone#822 to reproduce in our CI matrix and determine if this is specific to aarch64 macOS (I encountered this locally) or occurs on other platforms.
If I use --enable-experimental-jit=no instead, the build succeeds. Unfortunately, that means our configure flags are not the sole cause of the test_json failure. I suspect the segfault is a JIT interaction with LLVM 20. I'm not sure why I get this segfault in cpython but not in python-build-standalone. It's worth noting my clang versions do not match exactly.
However, the test_json failure cannot be caused by the JIT because it is occurring on our x86-64 macOS and free-threaded builds, which have the JIT disabled.
@zanieb Do you perhaps have a problematic build with PGO+LTO available for testing? I imagine you would need to disable the cjson test that triggers segfault to get past the profiling stage for PGO...
But it would be interesting to see if a) such a build also causes segfault in my test case from #139231, b) if it does, what the stack depth increments were between recursions. Could be that LTO causes a problem similar to #137573, and the cost of (the last) recursion step ends up exceeding the margin.
Indeed! I've disabled this test in order to release 3.15.0a1 in python-build-standalone so uv python install 3.15.0a1 will get you what you've requested. I'm not sure if the failure will occur when run outside of the profiling step, I haven't checked yet.
Can you try the example from #139231? (The recorded stack depth increments between recursion steps there are what is most interesting - i.e., whether they are suspiciously large).
Although if the test_json passes, it may be that the final PGO+LTO build is OK, and it is the intermediate (presumably just LTO-enabled) build that is problematic.
Those increments are in line what I would expect (aside from the fact that stack size is 8 MB and not 16 MB - I assume you are overriding the setting in your builds)?
It's also plausible that the instrumentation from PGO is causing the problem.
That's true; the instrumentation is likely to result in increased stack consumption per recursion. It would be interesting to see how much (i.e., if it exceeds the value of the margin). Do you have an easy way to run test.py with the intermediate (instrumented) build?
Have you tried increasing the depth from 200k to, say, 500k? Is it much slower?
If that doesn't fail, it implies that PGO is thinking that deep recursion is a hot path, and maybe turning the calls into tailcalls.
We don't need the test to raise a recursion error, just not crash. So we could remove the assertion.
The test for the recursion error is just to check that the test is hitting the stack limit.
Activity
vstinner commentedon Oct 14, 2025
I cannot reproduce this issue on x86-64 Linux with clang 20. I used these commands:
My clang version:
clang version 20.1.8 (Fedora 20.1.8-4.fc42).zanieb commentedon Oct 14, 2025
Thanks for trying to reproduce!
Just to be clear, my failure occurred while running the profile task, e.g., here, rather than during the test run after a successful build — so I'd expect it to fail during
make.We're specifically using clang 20.1.4 over in python-build-standalone. I tried to reproduce this on HEAD (2ca3c85) on my macOS machine with LLVM clang 20.1.3 from homebrew and could not — the build succeeded. I suspect there may be an interaction with another facet of our build system.
I've opened astral-sh/python-build-standalone#822 to reproduce in our CI matrix and determine if this is specific to aarch64 macOS (I encountered this locally) or occurs on other platforms.
zanieb commentedon Oct 14, 2025
astral-sh/python-build-standalone#822 confirms that this is only an issue on aarch64 and x86-64 macOS.
I tried to reproduce in cpython with build flags that more closely resemble python-build-standalone's
which requires the following patch to allow LLVM 20 in the JIT (we are currently using this in 3.14 without problem)
Unfortunately, this failed with a segfault
If I use
--enable-experimental-jit=noinstead, the build succeeds. Unfortunately, that means our configure flags are not the sole cause of thetest_jsonfailure. I suspect the segfault is a JIT interaction with LLVM 20. I'm not sure why I get this segfault in cpython but not in python-build-standalone. It's worth noting my clang versions do not match exactly.However, the
test_jsonfailure cannot be caused by the JIT because it is occurring on our x86-64 macOS and free-threaded builds, which have the JIT disabled.zanieb commentedon Oct 14, 2025
I cannot reproduce the segfault after running
make clean, so I think we can disregard that for now.zanieb commentedon Oct 14, 2025
Looking at the test case... the failure is at
cpython/Lib/test/test_json/test_recursion.py
Lines 74 to 79 in 77eade3
which is checking that there are not segfaults when parsing a deep object.
The recursion limit should be set to 20,000 (+ current depth)
cpython/Lib/test/support/__init__.py
Lines 2398 to 2409 in 41712c4
The object is an order of magnitude deeper, so we should be hitting the recursion limit.
Specifically, we're failing in the
cjsontest, so it's just the C-accelerated JSON implementation that has different behaviorcpython/Lib/test/test_json/__init__.py
Lines 23 to 29 in 872eafd
zanieb commentedon Oct 15, 2025
Applying the following patch to revert 7016044 from #139232 (cc @rokm and @markshannon) resolves the issue
You can see the CI pass in astral-sh/python-build-standalone#823
rokm commentedon Oct 18, 2025
@zanieb Do you perhaps have a problematic build with PGO+LTO available for testing? I imagine you would need to disable the cjson test that triggers segfault to get past the profiling stage for PGO...
But it would be interesting to see if a) such a build also causes segfault in my test case from #139231, b) if it does, what the stack depth increments were between recursions. Could be that LTO causes a problem similar to #137573, and the cost of (the last) recursion step ends up exceeding the margin.
zanieb commentedon Oct 18, 2025
Indeed! I've disabled this test in order to release 3.15.0a1 in python-build-standalone so
uv python install 3.15.0a1will get you what you've requested. I'm not sure if the failure will occur when run outside of the profiling step, I haven't checked yet.edit: I tried the questionable invocation
and the tests passed
rokm commentedon Oct 19, 2025
Can you try the example from #139231? (The recorded stack depth increments between recursion steps there are what is most interesting - i.e., whether they are suspiciously large).
Although if the
test_jsonpasses, it may be that the final PGO+LTO build is OK, and it is the intermediate (presumably just LTO-enabled) build that is problematic.zanieb commentedon Oct 19, 2025
(note I compiled the
stackpointer.dylibwith gcc as suggested there)It's also plausible that the instrumentation from PGO is causing the problem.
rokm commentedon Oct 19, 2025
Those increments are in line what I would expect (aside from the fact that stack size is 8 MB and not 16 MB - I assume you are overriding the setting in your builds)?
That's true; the instrumentation is likely to result in increased stack consumption per recursion. It would be interesting to see how much (i.e., if it exceeds the value of the margin). Do you have an easy way to run
test.pywith the intermediate (instrumented) build?zanieb commentedon Dec 2, 2025
I don't unfortunately. I presume it's doable via a patch but it doesn't sound trivial.
It looks like this affects 3.14.1 as well now.
markshannon commentedon Dec 3, 2025
Have you tried increasing the depth from 200k to, say, 500k? Is it much slower?
If that doesn't fail, it implies that PGO is thinking that deep recursion is a hot path, and maybe turning the calls into tailcalls.
We don't need the test to raise a recursion error, just not crash. So we could remove the assertion.
The test for the recursion error is just to check that the test is hitting the stack limit.
zanieb commentedon Dec 3, 2025
@markshannon that's an interesting idea. It looks like that resolves the issue astral-sh/python-build-standalone#901
pythongh-140125: Increase recursion depth for `test_json` from 200k t…
gh-140125: Increase object recursion depth for `test_json` from 200k …
pythongh-140125: Increase object recursion depth for `test_json` from…
[3.14] gh-140125: Increase object recursion depth for `test_json` fro…