GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-152240: Fix test_c_stack_unwind on Linux LoongArch builds by yzewei · Pull Request #152241 · python/cpython

Conversation

@yzewei

@yzewei yzewei commented Jun 26, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

Fix test_c_stack_unwind on Linux LoongArch builds.

This change teaches _testinternalcapi's manual frame-pointer unwinder about
the LoongArch frame layout. On LoongArch, the frame pointer is the caller's
stack pointer; the previous frame pointer is at fp[-2], and the return
address is at fp[-1].

It also adds -funwind-tables for Linux LoongArch clang builds. clang/LoongArch
emits .debug_frame but not runtime .eh_frame unwind tables by default, so
glibc backtrace() cannot unwind through CPython frames unless unwind tables
are requested.

Validated on Linux LoongArch64:

GCC build:

../cpython/configure --with-pydebug CC=gcc
make -j8
PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind

clang build with clang 20.1.8:

../cpython/configure --with-pydebug CC=clang
make -j8
PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind

Also verified that -funwind-tables makes CPython C objects contain
.eh_frame, and the GNU backtrace test passes.

  • Issue: test_c_stack_unwind fails on Linux LoongArch builds #152240

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@yzewei
yzewei requested review from AA-Turner, corona10, emmatyping, erlend-aasland and itamaro as code owners June 26, 2026 01:57
@python-cla-bot

python-cla-bot Bot commented Jun 26, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot mentioned this pull request Jun 26, 2026
test_c_stack_unwind fails on Linux LoongArch builds #152240
Closed
@bedevere-app bedevere-app Bot added the awaiting review label Jun 26, 2026
@yzewei

yzewei commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

Fix log:

Gcc:

PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind
== CPython 3.16.0a0 (heads/main-dirty:a00464bc33) [GCC 15.2.0 20250808]
== Linux-6.18.16-main-16k-loongarch64-with-glibc2.42 little-endian
== Python build: release
== cwd: /mnt/build-cpython-main-gcc-release/build/test_python_worker_480813æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources: all test resources are disabled, use -u option to unskip tests

Using random seed: 4035734376
0:00:00 load avg: 0.08 mem: 27.8 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 0.08 mem: 27.8 MiB [1/1] test_c_stack_unwind
test_gnu_backtrace_jit_frames_disappear_after_executor_free (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_jit_frames_disappear_after_executor_free) ... skipped 'JIT is not available'
test_gnu_backtrace_unwinds_through_jit_frames (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_unwinds_through_jit_frames) ... #00 0x7fffe3601470 -> other
#01 0x555558360384 -> python
#02 0x5555585569fc -> python
#03 0x55555855e82c -> python
#04 0x55555856d86c -> python
#05 0x555558360384 -> python
#06 0x5555585570a4 -> python
#07 0x555558563cbc -> python
#08 0x55555856d86c -> python
#09 0x555558360384 -> python
#10 0x5555585570a4 -> python
#11 0x555558563cbc -> python
#12 0x55555856d86c -> python
#13 0x555558360384 -> python
#14 0x5555585570a4 -> python
#15 0x555558563cbc -> python
#16 0x55555856d86c -> python
#17 0x555558360384 -> python
#18 0x5555585570a4 -> python
#19 0x555558563cbc -> python
#20 0x55555856d86c -> python
#21 0x555558360384 -> python
#22 0x5555585570a4 -> python
#23 0x555558563cbc -> python
#24 0x55555856d86c -> python
#25 0x555558360384 -> python
#26 0x5555585570a4 -> python
#27 0x555558563cbc -> python
#28 0x55555856d86c -> python
#29 0x555558360384 -> python
#30 0x5555585570a4 -> python
#31 0x555558563cbc -> python
#32 0x55555856d86c -> python
#33 0x555558360384 -> python
#34 0x5555585570a4 -> python
#35 0x555558563cbc -> python
#36 0x55555856d86c -> python
#37 0x555558360384 -> python
#38 0x5555585570a4 -> python
#39 0x555558563cbc -> python
#40 0x55555856d86c -> python
#41 0x555558360384 -> python
#42 0x555558360384 -> python
#43 0x5555585569fc -> python
#44 0x55555855e82c -> python
#45 0x55555856d510 -> python
#46 0x555558605d00 -> python
#47 0x55555860622c -> python
#48 0x555558608efc -> python
#49 0x555558644a6c -> python
#50 0x555558645a34 -> python
#51 0x7ffff22bd964 -> other
#52 0x7ffff22bda6c -> other
#53 0x5555582d694c -> python
{"length": 54, "python_frames": 51, "jit_frames": 0, "other_frames": 3, "jit_backend": null, "unwinder": "gnu_backtrace_unwind"}
ok
test_manual_unwind_finds_expected_frames (test.test_c_stack_unwind.ManualStackUnwindTests.test_manual_unwind_finds_expected_frames) ... #00 0x555558240384 -> python
#01 0x5555584369fc -> python
#02 0x55555843e82c -> python
#03 0x55555844d86c -> python
#04 0x555558240384 -> python
#05 0x5555584370a4 -> python
#06 0x555558443cbc -> python
#07 0x55555844d86c -> python
#08 0x555558240384 -> python
#09 0x5555584370a4 -> python
#10 0x555558443cbc -> python
#11 0x55555844d86c -> python
#12 0x555558240384 -> python
#13 0x5555584370a4 -> python
#14 0x555558443cbc -> python
#15 0x55555844d86c -> python
#16 0x555558240384 -> python
#17 0x5555584370a4 -> python
#18 0x555558443cbc -> python
#19 0x55555844d86c -> python
#20 0x555558240384 -> python
#21 0x5555584370a4 -> python
#22 0x555558443cbc -> python
#23 0x55555844d86c -> python
#24 0x555558240384 -> python
#25 0x5555584370a4 -> python
#26 0x555558443cbc -> python
#27 0x55555844d86c -> python
#28 0x555558240384 -> python
#29 0x5555584370a4 -> python
#30 0x555558443cbc -> python
#31 0x55555844d86c -> python
#32 0x555558240384 -> python
#33 0x5555584370a4 -> python
#34 0x555558443cbc -> python
#35 0x55555844d86c -> python
#36 0x555558240384 -> python
#37 0x5555584370a4 -> python
#38 0x555558443cbc -> python
#39 0x55555844d86c -> python
#40 0x555558240384 -> python
#41 0x555558240384 -> python
#42 0x5555584369fc -> python
#43 0x55555843e82c -> python
#44 0x55555844d510 -> python
#45 0x5555584e5d00 -> python
#46 0x5555584e622c -> python
#47 0x5555584e8efc -> python
#48 0x555558524a6c -> python
#49 0x555558525a34 -> python
#50 0x7ffff31dd964 -> other
#51 0x7ffff31dda6c -> other
#52 0x5555581b694c -> python
{"length": 53, "python_frames": 51, "jit_frames": 0, "other_frames": 2, "jit_backend": null, "unwinder": "manual_frame_pointer_unwind"}
ok

----------------------------------------------------------------------
Ran 3 tests in 1.347s

OK (skipped=1)
0:00:01 load avg: 0.08 mem: 28.3 MiB [1/1] test_c_stack_unwind passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 1.4 sec
Total tests: run=3 skipped=1
Total test files: run=1/1
Result: SUCCESS

Clang

PYTHON_JIT=0 ./python -m test -v test_c_stack_unwind
== CPython 3.16.0a0 (heads/main-dirty:a00464bc33) [Clang 20.1.8 ]
== Linux-6.18.16-main-16k-loongarch64-with-glibc2.42 little-endian
== Python build: debug
== cwd: /mnt/build-cpython-main-clang-debug/build/test_python_worker_480864æ
== CPU count: 8
== encodings: locale=UTF-8 FS=utf-8
== resources: all test resources are disabled, use -u option to unskip tests

Using random seed: 721941152
0:00:00 load avg: 0.02 mem: 31.4 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 0.02 mem: 31.4 MiB [1/1] test_c_stack_unwind
test_gnu_backtrace_jit_frames_disappear_after_executor_free (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_jit_frames_disappear_after_executor_free) ... skipped 'JIT is not available'
test_gnu_backtrace_unwinds_through_jit_frames (test.test_c_stack_unwind.GnuBacktraceUnwindTests.test_gnu_backtrace_unwinds_through_jit_frames) ... #00 0x7ffff008dea4 -> other
#01 0x555556ec1308 -> python
#02 0x555556e341e8 -> python
#03 0x555556ff546c -> python
#04 0x555556ffc0c8 -> python
#05 0x555556ff4adc -> python
#06 0x555556e341e8 -> python
#07 0x555556ff5a90 -> python
#08 0x555556ffdbd0 -> python
#09 0x555556ff4adc -> python
#10 0x555556e341e8 -> python
#11 0x555556ff5a90 -> python
#12 0x555556ffdbd0 -> python
#13 0x555556ff4adc -> python
#14 0x555556e341e8 -> python
#15 0x555556ff5a90 -> python
#16 0x555556ffdbd0 -> python
#17 0x555556ff4adc -> python
#18 0x555556e341e8 -> python
#19 0x555556ff5a90 -> python
#20 0x555556ffdbd0 -> python
#21 0x555556ff4adc -> python
#22 0x555556e341e8 -> python
#23 0x555556ff5a90 -> python
#24 0x555556ffdbd0 -> python
#25 0x555556ff4adc -> python
#26 0x555556e341e8 -> python
#27 0x555556ff5a90 -> python
#28 0x555556ffdbd0 -> python
#29 0x555556ff4adc -> python
#30 0x555556e341e8 -> python
#31 0x555556ff5a90 -> python
#32 0x555556ffdbd0 -> python
#33 0x555556ff4adc -> python
#34 0x555556e341e8 -> python
#35 0x555556ff5a90 -> python
#36 0x555556ffdbd0 -> python
#37 0x555556ff4adc -> python
#38 0x555556e341e8 -> python
#39 0x555556ff5a90 -> python
#40 0x555556ffdbd0 -> python
#41 0x555556ff4adc -> python
#42 0x555556e341e8 -> python
#43 0x555556ec1104 -> python
#44 0x555556e341e8 -> python
#45 0x555556ff546c -> python
#46 0x555556ffc0c8 -> python
#47 0x555556ff4adc -> python
#48 0x555556ff4714 -> python
#49 0x5555570e784c -> python
#50 0x5555570e4da0 -> python
#51 0x5555570e4a04 -> python
#52 0x55555711b6f8 -> python
#53 0x55555711bba8 -> python
#54 0x55555711bc0c -> python
#55 0x7ffff0f7d964 -> other
#56 0x7ffff0f7da6c -> other
#57 0x555556d8c9a4 -> python
{"length": 58, "python_frames": 55, "jit_frames": 0, "other_frames": 3, "jit_backend": null, "unwinder": "gnu_backtrace_unwind"}
ok
test_manual_unwind_finds_expected_frames (test.test_c_stack_unwind.ManualStackUnwindTests.test_manual_unwind_finds_expected_frames) ... #00 0x555556961308 -> python
#01 0x5555568d41e8 -> python
#02 0x555556a9546c -> python
#03 0x555556a9c0c8 -> python
#04 0x555556a94adc -> python
#05 0x5555568d41e8 -> python
#06 0x555556a95a90 -> python
#07 0x555556a9dbd0 -> python
#08 0x555556a94adc -> python
#09 0x5555568d41e8 -> python
#10 0x555556a95a90 -> python
#11 0x555556a9dbd0 -> python
#12 0x555556a94adc -> python
#13 0x5555568d41e8 -> python
#14 0x555556a95a90 -> python
#15 0x555556a9dbd0 -> python
#16 0x555556a94adc -> python
#17 0x5555568d41e8 -> python
#18 0x555556a95a90 -> python
#19 0x555556a9dbd0 -> python
#20 0x555556a94adc -> python
#21 0x5555568d41e8 -> python
#22 0x555556a95a90 -> python
#23 0x555556a9dbd0 -> python
#24 0x555556a94adc -> python
#25 0x5555568d41e8 -> python
#26 0x555556a95a90 -> python
#27 0x555556a9dbd0 -> python
#28 0x555556a94adc -> python
#29 0x5555568d41e8 -> python
#30 0x555556a95a90 -> python
#31 0x555556a9dbd0 -> python
#32 0x555556a94adc -> python
#33 0x5555568d41e8 -> python
#34 0x555556a95a90 -> python
#35 0x555556a9dbd0 -> python
#36 0x555556a94adc -> python
#37 0x5555568d41e8 -> python
#38 0x555556a95a90 -> python
#39 0x555556a9dbd0 -> python
#40 0x555556a94adc -> python
#41 0x5555568d41e8 -> python
#42 0x555556961104 -> python
#43 0x5555568d41e8 -> python
#44 0x555556a9546c -> python
#45 0x555556a9c0c8 -> python
#46 0x555556a94adc -> python
#47 0x555556a94714 -> python
#48 0x555556b8784c -> python
#49 0x555556b84da0 -> python
#50 0x555556b84a04 -> python
#51 0x555556bbb6f8 -> python
#52 0x555556bbbba8 -> python
#53 0x555556bbbc0c -> python
#54 0x7ffff028d964 -> other
#55 0x7ffff028da6c -> other
#56 0x55555682c9a4 -> python
{"length": 57, "python_frames": 55, "jit_frames": 0, "other_frames": 2, "jit_backend": null, "unwinder": "manual_frame_pointer_unwind"}
ok

----------------------------------------------------------------------
Ran 3 tests in 2.709s

OK (skipped=1)
0:00:02 load avg: 0.10 mem: 31.9 MiB [1/1] test_c_stack_unwind passed

== Tests result: SUCCESS ==

1 test OK.

Total duration: 2.8 sec
Total tests: run=3 skipped=1
Total test files: run=1/1
Result: SUCCESS
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner
vstinner approved these changes Jun 26, 2026
View reviewed changes

@vstinner vstinner left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

The change LGTM, even if I don't know LoongArch architecture.

The -funwind-tables compiler flag is only needed by GnuBacktraceUnwindTests of test_c_stack_unwind? If yes, is it really worth it to add .eh_frame unwind tables just for a test?

@diegorusso @pablogsal: What do you think about the -funwind-tables flag?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting review labels Jun 26, 2026
@yzewei

yzewei commented Jun 29, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor Author

The change LGTM, even if I don't know LoongArch architecture.

The -funwind-tables compiler flag is only needed by GnuBacktraceUnwindTests of test_c_stack_unwind? If yes, is it really worth it to add .eh_frame unwind tables just for a test?

@diegorusso @pablogsal: What do you think about the -funwind-tables flag?

Indeed, adding -funwind-tables for testing purposes was not sufficiently necessary, and I removed this change. Thanks for the review.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@yzewei
yzewei force-pushed the loongarch-clang-unwind branch from 0a7ad9f to 809c42d Compare June 29, 2026 01:10
@yzewei
pythongh-152240: Fix LoongArch frame pointer unwinding
50bb458
@yzewei
yzewei force-pushed the loongarch-clang-unwind branch from 809c42d to 50bb458 Compare June 29, 2026 05:37
@StanFromIreland StanFromIreland mentioned this pull request Jun 29, 2026
gh-151040: Fix test_c_stack_unwind on riscv64 #152370
Merged
StanFromIreland
StanFromIreland reviewed Jun 29, 2026
View reviewed changes
Comment thread Modules/_testinternalcapi.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@vstinner vstinner added the needs backport to 3.15 bugs and security fixes label Jun 29, 2026
@vstinner
vstinner merged commit 8458582 into python:main Jun 29, 2026
75 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@miss-islington-app

miss-islington-app Bot commented Jun 29, 2026

Copy link
Copy Markdown

Thanks @yzewei for the PR, and @vstinner for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the awaiting merge label Jun 29, 2026
@bedevere-app

bedevere-app Bot commented Jun 29, 2026

Copy link
Copy Markdown

GH-152578 is a backport of this pull request to the 3.15 branch.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 bugs and security fixes label Jun 29, 2026
@vstinner

vstinner commented Jun 29, 2026

Copy link
Copy Markdown
Member

I merged your change, thanks for the fix!

@yzewei:

Indeed, adding -funwind-tables for testing purposes was not sufficiently necessary, and I removed this change. Thanks for the review.

Hum, all test_c_stack_unwind tests still pass on LoongArch (without -funwind-tables)?

@StanFromIreland:

Please also expand this to all risc64, see the changes in #152370.

"Loongson moved to their own processor instruction set architecture (ISA) in 2021 (...) The ISA has been referred to as "a fork of MIPS64r6" due to a perceived lack of changes judging from instruction listings"

say https://en.wikipedia.org/wiki/Loongson#LoongArch

IMO LoongArch is different enough from RISC-V that it deserves to have its own code path.

StanFromIreland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@yzewei

yzewei commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

I merged your change, thanks for the fix!

@yzewei:

Indeed, adding -funwind-tables for testing purposes was not sufficiently necessary, and I removed this change. Thanks for the review.

Hum, all test_c_stack_unwind tests still pass on LoongArch (without -funwind-tables)?

@StanFromIreland:

Please also expand this to all risc64, see the changes in #152370.

"Loongson moved to their own processor instruction set architecture (ISA) in 2021 (...) The ISA has been referred to as "a fork of MIPS64r6" due to a perceived lack of changes judging from instruction listings"

say https://en.wikipedia.org/wiki/Loongson#LoongArch

IMO LoongArch is different enough from RISC-V that it deserves to have its own code path.

Thanks for merging these changes!

Regarding the comparison between LoongArch and RISC-V: LoongArch is an independent Instruction Set Architecture (ISA), as clearly explained in the wiki.

Regarding the -funwind-tables flag: Without this flag, Clang/LoongArch builds do not generate the .eh_frame unwind tables required at runtime; although this PR fixes the tests, parts relying on GNU backtrace() would still fail.

In contrast, with GCC/LoongArch builds, GNU backtrace() works correctly even without this flag.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Jul 10, 2026

Copy link
Copy Markdown
Member

Ping @yzewei: Can you please sign the CLA for the backport? See #152578 (comment).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@xry111

xry111 commented Oct 11, 2026

Copy link
Copy Markdown
Contributor

AFAIK unwinding via frame can work even without unwind tables given that all the frames have the same format that this PR has coded. Doing so is not related to unwind tables.

Unwinding via the tables will work when some frames are not canonical (for example, if a function does not call any other function the compiler can actually skip saving RA). But that will need an unwinder capable to parse the unwind table.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@StanFromIreland StanFromIreland StanFromIreland left review comments
@vstinner vstinner vstinner approved these changes
@erlend-aasland erlend-aasland Awaiting requested review from erlend-aasland
@corona10 corona10 Awaiting requested review from corona10
@AA-Turner AA-Turner Awaiting requested review from AA-Turner
@emmatyping emmatyping Awaiting requested review from emmatyping
@itamaro itamaro Awaiting requested review from itamaro

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@yzewei @vstinner @xry111 @StanFromIreland
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.