Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

GH-91079: Decouple C stack overflow checks from Python recursion checks.#96510

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
markshannon merged 10 commits intopython:mainfromfaster-cpython:stack-overflow-3
Oct 5, 2022

Conversation

@markshannon
Copy link
Member

@markshannonmarkshannon commentedSep 2, 2022
edited by bedevere-bot
Loading

@markshannonmarkshannon marked this pull request as ready for reviewSeptember 5, 2022 09:56
@markshannonmarkshannon added the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 5, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by@markshannon for commite8a1bed 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-botbedevere-bot removed the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 5, 2022
@markshannonmarkshannon added the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 5, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by@markshannon for commit7e21a74 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-botbedevere-bot removed the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 5, 2022
@markshannonmarkshannon added the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 6, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by@markshannon for commit65cca7d 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-botbedevere-bot removed the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 6, 2022
@markshannonmarkshannon added the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 13, 2022
@bedevere-bot
Copy link

🤖 New build scheduled with the buildbot fleet by@markshannon for commitd75797c 🤖

If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again.

@bedevere-botbedevere-bot removed the 🔨 test-with-buildbotsTest PR w/ buildbots; report in status section labelSep 13, 2022
@gpsheadgpshead self-assigned thisOct 4, 2022
#1,000 on most systems
limit=sys.getrecursionlimit()
code="lambda: "+"+".join(f"_number_{i}"foriinrange(limit))
#Need more than 256 variables to use EXTENDED_ARGS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I assume EXTENDED_ARGS has stack implications? explaining the "why" of this here would be useful.

# and is equal to recursion_limit when _gen_throw() calls
# PyErr_NormalizeException().
recurse(setrecursionlimit(depth + 2) - depth)
recurse(5000)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

There's a constant of5000 used in all sorts of tests for the same purpose of being "too high" for recursion with this PR. I suggest making this a namedtest.support constant and referring to it instead of mystery constants spread throughout the test suite.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

(and where other constants are derived from that to be higher or lower scale, use math from the main value?)

/* WASI has limited call stack. Python's recursion limit depends on code
layout, optimization, and WASI runtime. Wasmtime can handle about 700
recursions, sometimes less. 500 is a more conservative limit. */
#ifndefPy_DEFAULT_RECURSION_LIMIT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

ifndef C_RECURSION_LIMIT

# definePy_DEFAULT_RECURSION_LIMIT 1000
# endif
#endif
#definePy_DEFAULT_RECURSION_LIMIT 1000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

keep the ifndef around this, those exist to allow someone setting their own via CFLAGS.

Copy link
Member

@gpsheadgpshead left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

this tied in nicely with the 3.11 talk :)

@tacaswell
Copy link
Contributor

This broke compilation ofhttps://github.com/python-greenlet/greenlet/

✔ 20:08:04 $ gcc -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/tcaswell/.virtualenvs/bleeding/include -I/home/tcaswell/.pybuild/bleeding/include/python3.12 -c src/greenlet/greenlet.cpp -o build/temp.linux-x86_64-3.12/src/greenlet/greenlet.oIn file included from src/greenlet/greenlet_internal.hpp:19,                 from src/greenlet/greenlet.cpp:17:src/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::operator<<(const PyThreadState*)’:src/greenlet/greenlet_greenlet.hpp:826:37: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?  826 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;      |                                     ^~~~~~~~~~~~~~~      |                                     py_recursion_limitsrc/greenlet/greenlet_greenlet.hpp:826:63: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?  826 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;      |                                                               ^~~~~~~~~~~~~~~~~~~      |                                                               c_recursion_remainingsrc/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::operator>>(PyThreadState*)’:src/greenlet/greenlet_greenlet.hpp:859:13: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?  859 |     tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;      |             ^~~~~~~~~~~~~~~~~~~      |             c_recursion_remainingsrc/greenlet/greenlet_greenlet.hpp:859:43: error: ‘PyThreadState’ {aka ‘struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?  859 |     tstate->recursion_remaining = tstate->recursion_limit - this->recursion_depth;      |                                           ^~~~~~~~~~~~~~~      |                                           py_recursion_limitsrc/greenlet/greenlet_greenlet.hpp: In member function ‘void greenlet::PythonState::set_initial_state(const PyThreadState*)’:src/greenlet/greenlet_greenlet.hpp:886:37: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_limit’; did you mean ‘py_recursion_limit’?  886 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;      |                                     ^~~~~~~~~~~~~~~      |                                     py_recursion_limitsrc/greenlet/greenlet_greenlet.hpp:886:63: error: ‘const PyThreadState’ {aka ‘const struct _ts’} has no member named ‘recursion_remaining’; did you mean ‘c_recursion_remaining’?  886 |     this->recursion_depth = tstate->recursion_limit - tstate->recursion_remaining;      |                                                               ^~~~~~~~~~~~~~~~~~~      |                                                               c_recursion_remaining

Doing the renames as suggested by the compiler fixes it (although from reading the PR here, maybepy_recursion_remaining should be used instead ofc_recursion_remaining).

Is this an unintended side effect of this change and or does greenlets need to adapt?

@gpshead
Copy link
Member

Not being familiar with greenlet much I suspect it wantspy_recursion_remaining. This is a rather internal structure that changes between releases.https://docs.python.org/3.11/whatsnew/3.11.html has a change around these that you've adapted to inhttps://github.com/python-greenlet/greenlet/blob/master/src/greenlet/greenlet_greenlet.hpp#L825 so this isprobably just another one that we need to document in 3.12's "What's New".

@gpshead
Copy link
Member

BTW@tacaswell major kudos to you for testing against CPythonmain =)

@tacaswell
Copy link
Contributor

tacaswell commentedOct 7, 2022
edited
Loading

Thanks, I'll get a PR to greenlet done in the next few days (I am also barely familiar with greenlet but it is a dependency of a dependency of something I care about).

I have built a whole rube-goldberg machine to test CPythonmain (https://github.com/tacaswell/build_the_world).

@dimpase
Copy link
Contributor

This, more precisely7644935, has broken deeply recursive code which uses@cache decorator, see#112215

In such a setting,sys.setrecursionlimit() stops working (sic!)

@dimpase
Copy link
Contributor

dimpase commentedNov 18, 2023
edited
Loading

E.g. the very basic, really CS101, recursion speedup with cache

#  fib.pyimportsyssys.setrecursionlimit(2000)fromfunctoolsimportcache@cachedeffib(n):ifn<1:return0ifn==1:return1returnfib(n-1)+fib(n-2)print(fib(500))

got broken by this PR.

Perhaps needless to say, on the latest main branch,

--- a/Include/cpython/pystate.h+++ b/Include/cpython/pystate.h@@ -225,7 +225,7 @@ struct _ts { #  define Py_C_RECURSION_LIMIT 500 #else    // This value is duplicated in Lib/test/support/__init__.py-#  define Py_C_RECURSION_LIMIT 1500+#  define Py_C_RECURSION_LIMIT 3000 #endif

makes it work (I didn't try to find the minimal needed increase forPy_C_RECURSION_LIMIT)

$ ./python <fib.py139423224561697880139724382870407283950070256587697307264108962948325571622863290691557658876222521294125

@PeterLuschny

@gpshead
Copy link
Member

Please stop using this longmerged and closed PR as a forum, nobody liatens here. This is not an issue tracker.

If you believe there is a bug, file a new issue.

@dimpase
Copy link
Contributor

Please stop using this longmerged and closed PR as a forum, nobody liatens here. This is not an issue tracker.

If you believe there is a bug, file a new issue.

These are filed.
This was an attempt at heads-up here, after I learned of and worked on#112215, which explains why this PR introduced a bug (and a big one). I've also opened#112282 to point out at the undocumented behaviour this PR introduced.

I also don't understand why this was merged, while not conforming topython/steering-council#102 (they asked forMemoryError thrown on C stack limit violation, rather thanRecursionError)

inducer added a commit to inducer/loopy that referenced this pull requestFeb 16, 2024
On Python 3.12, this provokes a stack overflow in the scheduler. It isnot quite clear why that's the case; pure-Python recursion even withgenerators seems to respond well to setrecursionlimit():```pydef f(n):    if n:        yield from f(n-1)    else:        yield 5import syssys.setrecursionlimit(3500)print(list(f(3400)))```That said, there have been [behavior](python/cpython#96510)[changes](python/cpython#112215)in Py3.12 in this regard, but it is not clear what exactlyabout Loopy's behavior makes it fall into the 'bad' case.
inducer added a commit to inducer/loopy that referenced this pull requestAug 25, 2024
On Python 3.12, this provokes a stack overflow in the scheduler. It isnot quite clear why that's the case; pure-Python recursion even withgenerators seems to respond well to setrecursionlimit():```pydef f(n):    if n:        yield from f(n-1)    else:        yield 5import syssys.setrecursionlimit(3500)print(list(f(3400)))```That said, there have been [behavior](python/cpython#96510)[changes](python/cpython#112215)in Py3.12 in this regard, but it is not clear what exactlyabout Loopy's behavior makes it fall into the 'bad' case.
inducer added a commit to inducer/loopy that referenced this pull requestAug 25, 2024
On Python 3.12, this provokes a stack overflow in the scheduler. It isnot quite clear why that's the case; pure-Python recursion even withgenerators seems to respond well to setrecursionlimit():```pydef f(n):    if n:        yield from f(n-1)    else:        yield 5import syssys.setrecursionlimit(3500)print(list(f(3400)))```That said, there have been [behavior](python/cpython#96510)[changes](python/cpython#112215)in Py3.12 in this regard, but it is not clear what exactlyabout Loopy's behavior makes it fall into the 'bad' case.
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@gpsheadgpsheadgpshead approved these changes

@isidenticalisidenticalAwaiting requested review from isidenticalisidentical is a code owner

@iritkatrieliritkatrielAwaiting requested review from iritkatrieliritkatriel is a code owner

@rhettingerrhettingerAwaiting requested review from rhettingerrhettinger is a code owner

@tirantiranAwaiting requested review from tiran

Assignees

@gpsheadgpshead

Labels

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

5 participants

@markshannon@bedevere-bot@tacaswell@gpshead@dimpase

[8]ページ先頭

©2009-2025 Movatter.jp