-
-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Regression in 3.12 beta in json.dump deeply nested dict #107263
Comments
cc @markshannon |
Related #105003 |
Also cc @Yhg1s out of caution, since we're close to RC. At a minimum, I'm guessing we need a What's New |
The relevant number is the C stack, so depending on your numbers, note you don't need to set
|
I am in favor of adding a new API exposing this. Nothing else would fundamentally fix this. |
If we change the original example to: d = {}
for x in range(100_000):
d = {'k': d}
import json, sys
sys.setrecursionlimit(100_000_000)
foo = json.dumps(d) It segfaults on 3.11. Here are what we can do to lessen the impact of this change:
Whatever we do, I'll add a section to the "what's new". |
Something else we could do is to change the C recursion limit from 800 to 1500 on optimized builds, where the C frames will be smaller. A few tests will need changing to handle the differing recursion limits, but that's not a bad thing as it should make the tests more general. |
Can you elaborate on that?
People can easily increase their stack size on Unix-like systems with As OS provides this API, why would Python forbid users with real need? Other virtual machines like V8 (JavaScript runtime) can increase stack size on Unix-like systems (while not on Windows). Increasing stack size/recursion limit is a real need for some users, and this limit will be a problem without easy workaround. It breaks user's code without possibility of easy migration. |
I'd find that surprising, at the very least that would require changing
|
Alternative take: The json module shouldn't be using recursion. (Which is out of scope as an rc1 release blocker resolution) |
Don't presume this. System, policy, and container limits can constrain the maximum ulimit. And people dealing with untrusted data as is common both encoding or decoding json generally do not have test cases to determine what limits they require to not crash. People's expectations are reasonable that Python will never crash (segfault) the process due to a stack overflow. Another lack of control: Threads are frequently spawned by extension modules or embedding languages (C/C++/Rust) where the C stack size is configured by that code at thread creation time and can a lot smaller than the ulimit default main thread stack size for a variety of valid reasons. This can be pretty far removed from the control of the Python application user. |
I am not asking to remove this limit. I think it should be made configurable at least for professional users. Recursive deep is not an error if you have a large stack size. Also if you have a very small stack size, the current limit would cause seg fault either. Currently, the only workaround for this would be editing the source code and compiling again. That's too much even for professional users. |
Yep, understood. I do think that's a stack / recursion limit related feature request on its own that we should track and decide in its own issue. (feel free to file one) |
I tend to think it's a bug fix. If that's a feature request and got passed, then we can run such programs in 3.10, 3.11, and 3.13, which is very weird not having them on 3.12. |
…_EvalFrameDefault()` (GH-107535) * Set C recursion limit to 1500, set cost of eval loop to 2 frames, and compiler mutliply to 2.
…PyEval_EvalFrameDefault()` (pythonGH-107535) * Set C recursion limit to 1500, set cost of eval loop to 2 frames, and compiler mutliply to 2. (cherry picked from commit fa45958) Co-authored-by: Mark Shannon <mark@hotpy.org>
…_PyEval_EvalFrameDefault()` (GH-107535) (#107618) GH-107263: Increase C stack limit for most functions, except `_PyEval_EvalFrameDefault()` (GH-107535) * Set C recursion limit to 1500, set cost of eval loop to 2 frames, and compiler mutliply to 2. (cherry picked from commit fa45958) Co-authored-by: Mark Shannon <mark@hotpy.org>
Is there anything left to do? |
Assuming this is all fixed now. |
This has broken basic abilities of # fib.py
import sys
sys.setrecursionlimit(2000)
from functools import cache
@cache
def fib(n):
if n<1: return 0
if n==1: return 1
return fib(n-1) + fib(n-2)
print(fib(500)) Now
is quite quick (removing
By the way, increasing |
you still need to fix |
This was reported here: https://discuss.python.org/t/has-sys-setrecursionlimit-behaviour-changed-in-python-3-12b/30205
The following program works fine on 3.11, but crashes with RecursionError on 3.12:
I confirmed this bisects to #96510
Linked PRs
_PyEval_EvalFrameDefault()
#107535_PyEval_EvalFrameDefault()
(GH-107535) #107618The text was updated successfully, but these errors were encountered: