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 — fix finalizing and atexit timing by youknowone · Pull Request #6626 · RustPython/RustPython

Conversation

@youknowone

@youknowone youknowone commented Jan 2, 2026 •
edited by coderabbitai Bot
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes
    • Improved interpreter shutdown handling and suppressed unraisable hook invocations during VM finalization to ensure cleaner interpreter shutdown.

✏️ Tip: You can customize this high-level summary in your review settings.

Sorry, something went wrong.

Uh oh!

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

All reactions
@coderabbitai

coderabbitai Bot commented Jan 2, 2026 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

The interpreter finalization sequence is restructured to dynamically import the threading module and call threading._shutdown() during shutdown. Additionally, unraisable exception handling is suppressed when the VM is finalizing by checking the finalizing flag.

Changes

Cohort / File(s) Summary
Finalization Sequencing
crates/vm/src/vm/interpreter.rs
Replaced direct non-daemon thread wait with conditional dynamic threading module import and threading._shutdown() invocation. Updated finalization flag timing and documentation to reflect Py_FinalizeEx semantics.
Exception Handling During Shutdown
crates/vm/src/vm/mod.rs
Added early-return guard in run_unraisable() to suppress unraisable hook handling when VM is finalizing.

Sequence Diagram

sequenceDiagram
    participant VM as Virtual Machine
    participant Threading as Threading Module
    participant Atexit as Atexit System

    VM->>Threading: Attempt dynamic import
    alt Import Successful
        VM->>Threading: Call threading._shutdown()
        Threading-->>VM: Shutdown complete
    else Import Failed
        VM-->>VM: Continue
    end
    VM->>VM: Set finalizing flag = true
    VM->>Atexit: Run atexit functions
    Atexit-->>VM: Cleanup complete
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related PRs

  • Fix test_runpy #6409: Modifies Interpreter::finalize with changes to shutdown sequencing and return type handling, directly overlapping with main PR's finalization restructuring.
  • Add PythonFinallizationError and upgrade multiprocessing #6592: Adds VM finalizing flag guards to suppress behaviors during shutdown, sharing the same suppression pattern and finalization state management as this PR.
  • Upgrade threading to 3.13.11; sys.setprofile & impl more threading #6691: Introduces threading _shutdown implementation and VM threading state management, which directly implements the threading shutdown mechanism called by this PR's finalization logic.

Suggested Reviewers

  • fanninpm

🐰 The VM winds down with grace and care,
Threading module bids farewell in the air,
Atexit functions tidy up the floor,
Finalization flags mark the door,
A shutdown sequence, crisp and fair! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix atexit' directly relates to the main changes in the PR, which involve fixing atexit and finalization timing issues in the interpreter shutdown sequence.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
  • X
  • Mastodon
  • Reddit
  • LinkedIn

Comment @coderabbitai help to get the list of available commands and usage tips.

All reactions

Sorry, something went wrong.

Uh oh!

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

@fanninpm

fanninpm commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

You may want to take a look in test_bdb for 31 tests that can be un-skipped.

youknowone 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.

@fanninpm fanninpm mentioned this pull request Jan 13, 2026
Downgraded skips in tests #6716
Merged
@youknowone

youknowone commented Jan 14, 2026

Copy link
Copy Markdown
Member Author

let me check this again when #6718 is done

All reactions

Sorry, something went wrong.

Uh oh!

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

@youknowone
youknowone force-pushed the atexit branch from 96e9080 to ab5fde2 Compare January 17, 2026 12:24
@youknowone

youknowone commented Jan 17, 2026

Copy link
Copy Markdown
Member Author

@fanninpm they are downgraded to expectedFailure (@terryluan12 thanks!)
And this patch doesn't seem to be enough for that

All reactions

Sorry, something went wrong.

Uh oh!

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

@youknowone
youknowone marked this pull request as ready for review January 17, 2026 12:25
coderabbitai[bot]
coderabbitai Bot reviewed Jan 17, 2026
View reviewed changes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@crates/vm/src/vm/mod.rs`:
- Around line 552-562: The finalizing flag is set before calling
atexit::_run_exitfuncs, causing run_unraisable to early-return and suppress
atexit handler exceptions; either move the store to state.finalizing to after
atexit::_run_exitfuncs(vm) so finalization suppression happens post-atexit, or
add a small atexit bypass: introduce an atexit-running marker on VM state (e.g.,
vm.state.atexit_running) set around atexit::_run_exitfuncs and change
run_unraisable to allow reporting when that marker is true (while still
suppressing in other finalization contexts). Ensure references are to
run_unraisable, atexit::_run_exitfuncs, and state.finalizing (or the new
state.atexit_running) so reviewers can find and apply the change.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread crates/vm/src/vm/mod.rs
Comment on lines 552 to +562
pub fn run_unraisable(&self, e: PyBaseExceptionRef, msg: Option<String>, object: PyObjectRef) {
// Suppress unraisable exceptions during interpreter finalization.
// when daemon thread exceptions and
// __del__ errors are silently ignored during shutdown.
if self
.state
.finalizing
.load(std::sync::atomic::Ordering::Acquire)
{
return;
}

@coderabbitai coderabbitai Bot Jan 17, 2026

Copy link
Copy Markdown
Contributor

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.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's understand the context of this code
# Find where the finalizing flag is set and where atexit runs

cd crates/vm/src/vm
grep -n "finalizing" mod.rs | head -20

Repository: RustPython/RustPython

Length of output: 184


🏁 Script executed:

# Look for atexit-related code in the vm
grep -r "atexit" crates/vm/src --include="*.rs" | head -20

Repository: RustPython/RustPython

Length of output: 1449


🏁 Script executed:

# Find where finalizing is set to understand the order of operations
grep -r "finalizing.*=" crates/ --include="*.rs" -B2 -A2 | head -40

Repository: RustPython/RustPython

Length of output: 1454


🏁 Script executed:

# Look at the vm initialization and shutdown sequence
grep -n "fn run_unraisable\|fn finalize\|fn exit" crates/vm/src/vm/mod.rs | head -20

Repository: RustPython/RustPython

Length of output: 168


🏁 Script executed:

# Look at the finalization sequence in interpreter.rs
grep -n "finalizing\|atexit" crates/vm/src/vm/interpreter.rs | head -30

Repository: RustPython/RustPython

Length of output: 435


🏁 Script executed:

# Get more context around the finalization and atexit calls
sed -n '1,300p' crates/vm/src/vm/interpreter.rs | tail -100

Repository: RustPython/RustPython

Length of output: 3393


🏁 Script executed:

# Look at the full shutdown/exit handling sequence
rg "fn.*exit|fn.*finali" crates/vm/src/vm/interpreter.rs -A 10 | head -50

Repository: RustPython/RustPython

Length of output: 389


🌐 Web query:

CPython Py_FinalizeEx atexit exceptions handling unraisable hook

💡 Result:

Short summary — how CPython handles exceptions during Py_FinalizeEx / atexit and the unraisable hook

  • Py_FinalizeEx runs Python-level shutdown which includes running atexit handlers. Exceptions raised in atexit handlers produce a printed traceback (to sys.stderr) and the last non-SystemExit exception raised is re-raised after all handlers have run. [1][2]

  • C-level exit handlers (Py_AtExit) are separate: they are called by Py_FinalizeEx but run after Python internal finalization; they must not call Python APIs. Py_AtExit handlers are for C code, not Python-level cleanup. [3]

  • sys.unraisablehook (added in Python 3.8) is the configurable hook used for "unraisable exceptions" (e.g., exceptions in del, weakref callbacks, GC callbacks). By default Python logs these to sys.stderr; you can override sys.unraisablehook to customize handling. [4]

  • Important caveat: some "unraisable" errors occur very late in interpreter finalization (after core modules like sys and stderr have been cleared). In that case the custom sys.unraisablehook cannot be called and the error may go unreported (PyErr_WriteUnraisable may be a no‑op if stderr/sys are gone). This limitation is documented and tracked in the issue thread that introduced sys.unraisablehook. [4][5]

Practical implications

  • Do not call Py_FinalizeEx recursively or from code that may run during shutdown (atexit handlers, del, etc.). The docs explicitly warn against that. [3]
  • If you need reliable reporting of errors during shutdown, avoid relying on very-late finalizers; prefer earlier, explicit cleanup or handle errors before finalization. [3][1][4]

Sources
[1] atexit — Exit handlers (Python docs).
[2] atexit behavior / examples (Python docs, PyMotW).
[3] Initialization, Finalization, and Threads / Py_AtExit (CPython C-API docs).
[4] Issue and PR discussion and docs for sys.unraisablehook (bpo-36829 / sys docs / Victor Stinner blog).
[5] Python tracker discussion about very-late unraisable exceptions during finalization.


Atexit exceptions are being suppressed during finalization, which differs from CPython's behavior.

RustPython sets the finalizing flag at line 143, before calling atexit::_run_exitfuncs(vm) at line 146. This causes the run_unraisable call in atexit handlers to return early and suppress exception reporting. CPython still prints atexit handler exceptions to stderr during finalization, making them visible for debugging. Consider either moving the finalizing flag to after atexit completion, or adding a special case in run_unraisable to allow atexit exceptions to bypass the finalization suppression.

🤖 Prompt for AI Agents
In `@crates/vm/src/vm/mod.rs` around lines 552 - 562, The finalizing flag is set
before calling atexit::_run_exitfuncs, causing run_unraisable to early-return
and suppress atexit handler exceptions; either move the store to
state.finalizing to after atexit::_run_exitfuncs(vm) so finalization suppression
happens post-atexit, or add a small atexit bypass: introduce an atexit-running
marker on VM state (e.g., vm.state.atexit_running) set around
atexit::_run_exitfuncs and change run_unraisable to allow reporting when that
marker is true (while still suppressing in other finalization contexts). Ensure
references are to run_unraisable, atexit::_run_exitfuncs, and state.finalizing
(or the new state.atexit_running) so reviewers can find and apply the change.

Sorry, something went wrong.

Uh oh!

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

All reactions
@youknowone
youknowone marked this pull request as draft January 17, 2026 14:31
youknowone added 2 commits January 17, 2026 23:41
@youknowone
fix finalizing and atexit timing
cdf4c6f
@youknowone
fix shutdown
0b8ce97
@youknowone
youknowone force-pushed the atexit branch from ab5fde2 to 0b8ce97 Compare January 17, 2026 14:41
@youknowone
youknowone marked this pull request as ready for review January 17, 2026 16:25
@youknowone
youknowone merged commit 11c9b0e into RustPython:main Jan 17, 2026
13 checks passed

Uh oh!

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

@youknowone
youknowone deleted the atexit branch January 17, 2026 16:54
@youknowone youknowone changed the title fix atexit fix finalizing and atexit timing Jan 17, 2026
@fanninpm

fanninpm commented Jan 17, 2026

Copy link
Copy Markdown
Contributor

they are downgraded to expectedFailure

That's better than nothing!

All reactions

Sorry, something went wrong.

Uh oh!

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

@coderabbitai coderabbitai Bot mentioned this pull request Feb 1, 2026
dealloc and finalize_modules #6934
Merged
This was referenced Mar 4, 2026
Stop non-main threads during interpreter finalization #7349
Merged
Fix atexit unraisable exception message format #7399
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@coderabbitai coderabbitai[bot] coderabbitai[bot] left review comments

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.

2 participants

@youknowone @fanninpm
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 01402520 — 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.