Skip to content

Conversation

stefanor
Copy link
Contributor

@stefanor stefanor commented Oct 13, 2025

Adapted from a patch for Python 3.14 submitted to the Debian BTS by John David Anglin https://bugs.debian.org/1105111#20

The backport to the 3.14 branch is non-trivial as some of the affected code was refactored in 7094f09 but the patch in the Debian BTS was targetted at 3.14 and can be referenced to backport.

@picnixz
Copy link
Member

picnixz commented Oct 13, 2025

No news, as this is a simple regression fix

Please do so. A regression fix needs to be announced so that users know that their bug has been indeed fixed.

@picnixz picnixz changed the title GH-139914: On HPPA, the stack grows up GH-139914: Handle stack growth direction on HPPA Oct 13, 2025
picnixz
picnixz previously approved these changes Oct 13, 2025
Python/ceval.c Outdated
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#ifdef __hppa__
if (here_addr <= _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES) {
Copy link
Member

Choose a reason for hiding this comment

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

Can't we pre-compute the bound?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The immediate answer is: No because margin_count is a function parameter.

However... This is always set to 1, so it could be removed...

Copy link
Member

Choose a reason for hiding this comment

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

Sorry, I meant to avoid computing twice _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES to avoid having a double ifdef in this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

_Py_InitializeRecursionLimits() can change the limits if c_stack_hard_limit == 0 (I assume that's the uninitialized state)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can pre-compute margin_count * _PyOS_STACK_MARGIN_BYTES (used 4 times in the source) potentially saving a multiply.

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 that's the uninitialized state

That's also something I actually find weird. If we're in an uninitialized state, how come can we use the soft limit? anyway, let's leave the code as is as it could actually be less readable in the end and introduce a subtle issue if _Py_InitializeRecursionLimits could change the soft limit value at that point.

Copy link
Contributor Author

@stefanor stefanor Oct 13, 2025

Choose a reason for hiding this comment

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

Come to think of it, we only hit that second if block if we pass the first one. Given that we're reversing the direction of the comparison, on HPPA we won't get here if c_stack_soft_limit is 0.

@markshannon: Why do we call _Py_InitializeRecursionLimits here?

Copy link
Member

Choose a reason for hiding this comment

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

Because this in an API function, and the stack limits might not have been initialized.
Maybe we are being overly conservative, but it is harmless to check.

Copy link
Contributor Author

@stefanor stefanor Oct 14, 2025

Choose a reason for hiding this comment

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

Don't we risk never reaching never reaching the initialisation check on most platforms, if c_stack_soft_limit is 0? (And possibly on HPPA too, due to underflow of an unsigned int)

It seems like this whole first if block should just be removed.

Copy link
Member

@markshannon markshannon left a comment

Choose a reason for hiding this comment

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

The general implementation looks sound.

Rather than mysterious #ifdef __hppa__ could you #define STACK_GROWS_DOWN in the config and use #if STACK_GROWS_DOWN for clarity and to keep things tidy in case any other platform has a stack the grows up.

OOI what is hppa? Is this PA-RISC, or some new variant?

Python/ceval.c Outdated
uintptr_t here_addr = _Py_get_machine_stack_pointer();
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
#ifdef __hppa__
if (here_addr <= _tstate->c_stack_soft_limit - margin_count * _PyOS_STACK_MARGIN_BYTES) {
Copy link
Member

Choose a reason for hiding this comment

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

Because this in an API function, and the stack limits might not have been initialized.
Maybe we are being overly conservative, but it is harmless to check.

@bedevere-app
Copy link

bedevere-app bot commented Oct 14, 2025

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@stefanor
Copy link
Contributor Author

OOI what is hppa? Is this PA-RISC, or some new variant?

Yes, it is. Still going as Debian port. The newest hardware is 20 years old at this point, but the port is still alive. It'll probably keep going as long as GCC and Linux support it.

@stefanor stefanor requested a review from markshannon October 14, 2025 16:07
@encukou
Copy link
Member

encukou commented Oct 17, 2025

Thank you for upstreaming the patch!

Do the tests pass on HPPA? I would think that TestRecursion in Lib/test/test_call.py needs an update too.

I've sent a PR to your branch to expose _Py_STACK_GROWS_DOWN to Python tests (as _testcapi._Py_STACK_GROWS_DOWN), and to the rest of CPython (through Autuconf).


This PR will conflict with #139668, which will take some time to approve as it adds new API. If this PR is not urgent, I think it's best to wait for #139668, then rebase this one and ask you to check the result. Does that sound OK?

@python-cla-bot
Copy link

python-cla-bot bot commented Oct 19, 2025

All commit authors signed the Contributor License Agreement.

CLA signed

@stefanor
Copy link
Contributor Author

Do the tests pass on HPPA?

I had run the tests and seen enough failures that I assumed HPPA was already in a bad state re tests. I'm afraid we don't run them automatically in Debian due to limited hardware capacity.

@thesamesam
Copy link
Contributor

We have some skips on our end for HPPA but it's in a reasonable state overall. I haven't rechecked with this patch though.

(I just mention this in case someone stumbles upon it in future and thinks Python is broken there, as it isn't.)

fi
AC_SUBST([MULTIARCH_CPPFLAGS])

# Guess C stack direction
Copy link
Member

Choose a reason for hiding this comment

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

Is ‘guess’ the right word here?

Copy link
Member

Choose a reason for hiding this comment

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

Yes. For an arbitrary platform we can't really be sure.

@AA-Turner
Copy link
Member

@stefanor please don't force-push, per guidance in devguide etc.

A

@stefanor
Copy link
Contributor Author

I checked the test state more thoroughly. The 3.13 branch (08a2b2d) only has a single failure, but there's a lot in this branch. It looks like we have a GC bug to find.

https://gist.github.com/stefanor/393e358310b4dd791f6cbd2397fdcd58

@stefanor
Copy link
Contributor Author

stefanor commented Oct 20, 2025

@stefanor please don't force-push, per guidance in devguide etc.

Sorry, I try to keep my changes as a readable series of commits. I forgot the local rules here :)
(I mostly work in GitLab where you can diff between pushes)

@stefanor
Copy link
Contributor Author

It looks like we have a GC bug to find.

Bisection of test_gc failure takes me to 44e4c47 - where I found one more stack computation.

@stefanor
Copy link
Contributor Author

Much better:

== Tests result: FAILURE then FAILURE ==

10 slowest tests:
- test.test_concurrent_futures.test_process_pool: 9 min 53 sec
- test_regrtest: 7 min 43 sec
- test_tarfile: 7 min 37 sec
- test_zipfile: 7 min 26 sec
- test_fstring: 7 min 23 sec
- test.test_multiprocessing_spawn.test_manager: 6 min 53 sec
- test.test_multiprocessing_spawn.test_misc: 6 min 14 sec
- test_multiprocessing_main_handling: 6 min 11 sec
- test_ssl: 5 min 51 sec
- test_compileall: 5 min 3 sec

24 tests skipped:
    test.test_asyncio.test_windows_events
    test.test_asyncio.test_windows_utils test.test_gdb.test_backtrace
    test.test_gdb.test_cfunction test.test_gdb.test_cfunction_full
    test.test_gdb.test_misc test.test_gdb.test_pretty_print
    test.test_os.test_windows test_android test_apple test_devpoll
    test_free_threading test_kqueue test_launcher test_msvcrt
    test_perf_profiler test_perfmaps test_samply_profiler
    test_startfile test_winapi test_winconsoleio test_winreg
    test_winsound test_wmi

4 tests skipped (resource denied):
    test_peg_generator test_tkinter test_ttk test_zipfile64

9 re-run tests:
    test.test_asyncio.test_ssl
    test.test_multiprocessing_forkserver.test_processes
    test.test_multiprocessing_spawn.test_processes test_capi
    test_ctypes test_profiling test_socket test_struct test_tools

8 tests failed:
    test.test_asyncio.test_ssl
    test.test_multiprocessing_spawn.test_processes test_capi
    test_ctypes test_profiling test_socket test_struct test_tools

459 tests OK.

Total duration: 1 hour 59 min
Total tests: run=46,818 failures=47 skipped=1,948
Total test files: run=500/495 failed=8 skipped=24 resource_denied=4 rerun=9

stefanor added a commit to stefanor/cpython that referenced this pull request Oct 22, 2025
While looking at python#140028 I found some unrelated test regressions in the
3.14 cycle. These seem to all come from python#130317. From what I can tell,
that made Python more correct than it was before. According to [0] HP PA
RISC uses 1 for SNaN and thus a 0 for QNaN.

Update tests to expect this.

[0]: https://grouper.ieee.org/groups/1788/email/msg03272.html
stefanor added a commit to stefanor/cpython that referenced this pull request Oct 22, 2025
While looking at python#140028 I found some test failures that are caused by
new tests (from python#138122) running too slowly.

This adds an arbitrary heuristic to double the sampling run time.
We could do 10x instead? And/or move the heuristic into test_support.
Thoughts?
stefanor added a commit to stefanor/cpython that referenced this pull request Oct 22, 2025
While looking at python#140028 I found some test failures that are caused by
new tests (from python#138122) running too slowly.

This adds an arbitrary heuristic to double the sampling run time.
We could do 10x instead? And/or move the heuristic into test_support.
Thoughts?
stefanor added a commit to stefanor/cpython that referenced this pull request Oct 22, 2025
While looking at python#140028 I found some test failures that are caused by
new tests (from python#138122) running too slowly.

This adds an arbitrary heuristic to 10x the sampling run time (to the
default value of 10 seconds). Doubling the 1-second duration was
sufficient for my HP PA tests, but Fedora reported one of the 2-second
durations being too slow for a freethreaded build.

This heuristic could move into test_support. Thoughts?
vstinner pushed a commit that referenced this pull request Oct 22, 2025
While looking at #140028, I found some unrelated test regressions in the
3.14 cycle. These seem to all come from #130317. From what I can tell,
that made Python more correct than it was before. According to [0], HP PA
RISC uses 1 for SNaN and thus a 0 for QNaN.

[0]: https://grouper.ieee.org/groups/1788/email/msg03272.html
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Oct 22, 2025
While looking at pythonGH-140028, I found some unrelated test regressions in the
3.14 cycle. These seem to all come from pythonGH-130317. From what I can tell,
that made Python more correct than it was before. According to [0], HP PA
RISC uses 1 for SNaN and thus a 0 for QNaN.

[0]: https://grouper.ieee.org/groups/1788/email/msg03272.html
(cherry picked from commit 76fea5596c235a7853cda8df87c3998d506e950c)

Co-authored-by: Stefano Rivera <[email protected]>
vstinner pushed a commit that referenced this pull request Oct 22, 2025
…40467)

gh-130317: Fix SNaN broken tests on HP PA RISC (GH-140452)

While looking at GH-140028, I found some unrelated test regressions in the
3.14 cycle. These seem to all come from GH-130317. From what I can tell,
that made Python more correct than it was before. According to [0], HP PA
RISC uses 1 for SNaN and thus a 0 for QNaN.

[0]: https://grouper.ieee.org/groups/1788/email/msg03272.html
(cherry picked from commit 76fea55)

Co-authored-by: Stefano Rivera <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

7 participants