Skip to content

[Python] Fix crash unpickling a ROOT object without importing cppyy - #22968

Merged
guitargeek merged 1 commit into
root-project:masterfrom
guitargeek:root_pickle
Jul 31, 2026
Merged

[Python] Fix crash unpickling a ROOT object without importing cppyy#22968
guitargeek merged 1 commit into
root-project:masterfrom
guitargeek:root_pickle

Conversation

@guitargeek

Copy link
Copy Markdown
Contributor

Unpickling a ROOT object resolves its reduce callable ROOT.libROOTPythonizations._CPPInstance__expand__, which only imports the ROOT pythonizations extension and not the cppyy backend. It then enters CPyCppyy through the public API (Instance_FromVoidPtr) to rebuild the object.

In that state, CPyCppyy::Initialize() only imported the cppyy module in the branch taken when Python was not yet initialized. When Python is already running (the normal unpickling case), that branch is skipped and Initialize() returned success without ever importing cppyy, leaving gThisModule null. CreateScopeProxy() then dereferenced it as a fake scope and crashed with a segmentation violation.

Ensure the cppyy extension module is imported whenever gThisModule is still null, so the public API is usable regardless of how CPyCppyy was entered.

Add a regression test that pickles a ROOT object and reads it back in a fresh interpreter where cppyy has not been imported yet.

🤖 Done with the help of AI.

Addresses a problem described on the forum:

@vepadulano

Copy link
Copy Markdown
Member

Note that I already described this behaviour at #22749

@vepadulano vepadulano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! The changes look good per se but I wanted to ask two clarifications first

Comment thread bindings/pyroot/cppyy/CPyCppyy/src/API.cxx
Comment thread bindings/pyroot/cppyy/CPyCppyy/src/API.cxx
Unpickling a ROOT object resolves its reduce callable
`ROOT.libROOTPythonizations._CPPInstance__expand__`, which only imports
the ROOT pythonizations extension and not the cppyy backend. It then
enters CPyCppyy through the public API (Instance_FromVoidPtr) to rebuild
the object.

In that state, `CPyCppyy::Initialize()` only imported the cppyy module
in the branch taken when Python was not yet initialized. When Python is
already running (the normal unpickling case), that branch is skipped and
`Initialize()` returned success without ever importing cppyy, leaving
gThisModule null. `CreateScopeProxy()` then dereferenced it as a fake
scope and crashed with a segmentation violation.

Ensure the cppyy extension module is imported whenever `gThisModule` is
still null, so the public API is usable regardless of how CPyCppyy was
entered.

Add a regression test that pickles a ROOT object and reads it back in a
fresh interpreter where cppyy has not been imported yet.

🤖 Done with the help of AI.
@github-actions

Copy link
Copy Markdown

Test Results

    23 files      23 suites   3d 14h 25m 24s ⏱️
 3 882 tests  3 882 ✅ 0 💤 0 ❌
79 062 runs  79 062 ✅ 0 💤 0 ❌

Results for commit 5de287b.

@vepadulano vepadulano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you!

@guitargeek
guitargeek merged commit f2e0f52 into root-project:master Jul 31, 2026
37 of 38 checks passed
@guitargeek
guitargeek deleted the root_pickle branch July 31, 2026 12:27
@guitargeek

Copy link
Copy Markdown
Contributor Author

/backport to 6.40

@root-project-bot

Copy link
Copy Markdown

Preparing to backport PR #22968 to branch 6.40 requested by guitargeek

@root-project-bot

Copy link
Copy Markdown

Something went wrong with the creation of the PR to backport to 6.40: @guitargeek please see the logs

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants