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-142349: Fix refcount corruption in lazy import specialization by pablogsal · Pull Request #144733 · python/cpython

Conversation

@pablogsal

@pablogsal pablogsal commented Feb 12, 2026 •
edited by bedevere-app Bot
Loading

Uh oh!

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

Copy link
Copy Markdown
Member

_PyDict_LookupIndexAndValue() returns a borrowed reference via _Py_dict_lookup(), but specialize_load_global_lock_held() called Py_DECREF(value) on it when bailing out for lazy imports. Each time the adaptive counter fired while a lazy import was still in globals, this stole one reference from the dict's object. With 8+ threads racing through LOAD_GLOBAL during concurrent lazy import resolution, enough triggers accumulated to drive the refcount to zero while the dict and other threads still referenced the object, causing use-after-free.

  • Issue: Implement PEP 810 – Explicit lazy imports #142349

Sorry, something went wrong.

Uh oh!

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

All reactions
@pablogsal
pablogsal requested a review from brettcannon as a code owner February 12, 2026 08:26
@pablogsal
pablogsal requested a review from DinoV February 12, 2026 08:26
@pablogsal
pablogsal requested a review from ericsnowcurrently as a code owner February 12, 2026 08:26
@pablogsal
pablogsal requested a review from Yhg1s February 12, 2026 08:26
@pablogsal
pablogsal requested review from kumaraditya303, ncoghlan and warsaw as code owners February 12, 2026 08:26
@bedevere-app bedevere-app Bot added the awaiting core review label Feb 12, 2026
@pablogsal pablogsal changed the title gh-142351: Fix refcount corruption in lazy import specialization gh-142349: Fix refcount corruption in lazy import specialization Feb 12, 2026
@bedevere-app bedevere-app Bot mentioned this pull request Feb 12, 2026
Implement PEP 810 – Explicit lazy imports #142349
Closed
@pablogsal
pablogsal force-pushed the lazy-cleanup-2 branch from 3007570 to 239c717 Compare February 12, 2026 08:26
pablogsal
pablogsal commented Feb 12, 2026
View reviewed changes
Comment thread Python/import.c Resolved

Uh oh!

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

Yhg1s
Yhg1s reviewed Feb 12, 2026
View reviewed changes

@Yhg1s Yhg1s 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.

I don't think this is good enough for a free-threaded build. The error case happens when _PyImport_LoadLazyImportTstate is called with a borrowed reference. The GIL won't be protecting that borrowed reference in a free-threaded build, so the INCREF already happens too late. We need the caller to acquire an owned reference instead, in a safe way. But... where does this happen? As far as I can tell the callers all own the reference they pass.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread Include/internal/pycore_lazyimportobject.h Resolved

Uh oh!

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

Comment thread Python/import.c Resolved

Uh oh!

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

Comment thread Python/import.c Resolved

Uh oh!

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

@pablogsal
pablogsal marked this pull request as draft February 12, 2026 10:49
@bedevere-app bedevere-app Bot removed the awaiting core review label Feb 12, 2026
@pablogsal

pablogsal commented Feb 12, 2026

Copy link
Copy Markdown
Member Author

But... where does this happen? As far as I can tell the callers all own the reference they pass.

If that were true then there would not be crashes no?

All reactions

Sorry, something went wrong.

Uh oh!

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

@Yhg1s

Yhg1s commented Feb 12, 2026

Copy link
Copy Markdown
Member

If that were true then there would not be crashes no?

Unless the problem is actually something different, yes :) I would like to know which it is.

All reactions

Sorry, something went wrong.

Uh oh!

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

@pablogsal
pablogsal force-pushed the lazy-cleanup-2 branch from ca6f0f9 to 2fe3763 Compare February 12, 2026 11:13
@pablogsal pablogsal added the skip news label Feb 12, 2026
@pablogsal
Remove spurious Py_DECREF on borrowed ref in LOAD_GLOBAL specialization
c7defe2
_PyDict_LookupIndexAndValue() returns a borrowed reference via
_Py_dict_lookup(), but specialize_load_global_lock_held() called
Py_DECREF(value) on it when bailing out for lazy imports. Each time
the adaptive counter fired while a lazy import was still in globals,
this stole one reference from the dict's object. With 8+ threads
racing through LOAD_GLOBAL during concurrent lazy import resolution,
enough triggers accumulated to drive the refcount to zero while the
dict and other threads still referenced the object, causing
use-after-free.
@pablogsal
pablogsal force-pushed the lazy-cleanup-2 branch from 2fe3763 to c7defe2 Compare February 12, 2026 11:17
@pablogsal
pablogsal marked this pull request as ready for review February 12, 2026 11:21
@bedevere-app bedevere-app Bot added the awaiting core review label Feb 12, 2026
@pablogsal

pablogsal commented Feb 12, 2026

Copy link
Copy Markdown
Member Author

If that were true then there would not be crashes no?

Unless the problem is actually something different, yes :) I would like to know which it is.

Narrator: and the problem was indeed something different. Kind of

All reactions

Sorry, something went wrong.

Uh oh!

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

Yhg1s
Yhg1s approved these changes Feb 12, 2026
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Feb 12, 2026
@Yhg1s
Yhg1s enabled auto-merge (squash) February 12, 2026 11:22
kumaraditya303
kumaraditya303 approved these changes Feb 12, 2026
View reviewed changes
@Yhg1s
Yhg1s merged commit 072cd7c into python:main Feb 12, 2026
51 checks passed

Uh oh!

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

@bedevere-app bedevere-app Bot removed the awaiting merge label Feb 12, 2026
@robsdedude robsdedude mentioned this pull request Feb 12, 2026
Circular lazy import results in a crash #144727
Closed
thunder-coding pushed a commit to thunder-coding/cpython that referenced this pull request Feb 15, 2026
@pablogsal @thunder-coding
pythongh-142349: Fix refcount corruption in lazy import specialization (
8ce6ef7
python#144733)

Remove spurious Py_DECREF on borrowed ref in LOAD_GLOBAL specialization

_PyDict_LookupIndexAndValue() returns a borrowed reference via
_Py_dict_lookup(), but specialize_load_global_lock_held() called
Py_DECREF(value) on it when bailing out for lazy imports. Each time
the adaptive counter fired while a lazy import was still in globals,
this stole one reference from the dict's object. With 8+ threads
racing through LOAD_GLOBAL during concurrent lazy import resolution,
enough triggers accumulated to drive the refcount to zero while the
dict and other threads still referenced the object, causing
use-after-free.
pablogsal added a commit to pablogsal/cpython that referenced this pull request Feb 15, 2026
@pablogsal
pythongh-144727: Add test for circular lazy import crash (python#144727)
663c89f
Add a regression test ensuring that circular lazy imports raise a proper
error (ImportCycleError) instead of crashing with a segfault. The crash
was fixed in pythongh-144733 but no test was added at the time.
@pablogsal pablogsal mentioned this pull request Feb 15, 2026
gh-144727: Add test for circular lazy import crash (#144727) #144838
Merged
pablogsal added a commit to pablogsal/cpython that referenced this pull request Feb 15, 2026
@pablogsal
pythongh-144727: Add test for circular lazy import crash (python#144727)
e8ea062
Add a regression test ensuring that circular lazy imports raise a proper
error (ImportCycleError) instead of crashing with a segfault. The crash
was fixed in pythongh-144733 but no test was added at the time.
pablogsal added a commit that referenced this pull request Feb 15, 2026
@pablogsal
gh-144727: Add test for circular lazy import crash (#144727) (#144838)
5fe139c
Add a regression test ensuring that circular lazy imports raise a proper
error (ImportCycleError) instead of crashing with a segfault. The crash
was fixed in gh-144733 but no test was added at the time.
brijkapadia pushed a commit to brijkapadia/cpython that referenced this pull request Feb 28, 2026
@pablogsal @brijkapadia
pythongh-142349: Fix refcount corruption in lazy import specialization (
a46495c
python#144733)

Remove spurious Py_DECREF on borrowed ref in LOAD_GLOBAL specialization

_PyDict_LookupIndexAndValue() returns a borrowed reference via
_Py_dict_lookup(), but specialize_load_global_lock_held() called
Py_DECREF(value) on it when bailing out for lazy imports. Each time
the adaptive counter fired while a lazy import was still in globals,
this stole one reference from the dict's object. With 8+ threads
racing through LOAD_GLOBAL during concurrent lazy import resolution,
enough triggers accumulated to drive the refcount to zero while the
dict and other threads still referenced the object, causing
use-after-free.
brijkapadia pushed a commit to brijkapadia/cpython that referenced this pull request Feb 28, 2026
@pablogsal @brijkapadia
pythongh-144727: Add test for circular lazy import crash (python#144727…
baa8a32
…) (python#144838)

Add a regression test ensuring that circular lazy imports raise a proper
error (ImportCycleError) instead of crashing with a segfault. The crash
was fixed in pythongh-144733 but no test was added at the time.
ljfp pushed a commit to ljfp/cpython that referenced this pull request Apr 25, 2026
@pablogsal @ljfp
pythongh-142349: Fix refcount corruption in lazy import specialization (
3373e61
python#144733)

Remove spurious Py_DECREF on borrowed ref in LOAD_GLOBAL specialization

_PyDict_LookupIndexAndValue() returns a borrowed reference via
_Py_dict_lookup(), but specialize_load_global_lock_held() called
Py_DECREF(value) on it when bailing out for lazy imports. Each time
the adaptive counter fired while a lazy import was still in globals,
this stole one reference from the dict's object. With 8+ threads
racing through LOAD_GLOBAL during concurrent lazy import resolution,
enough triggers accumulated to drive the refcount to zero while the
dict and other threads still referenced the object, causing
use-after-free.
ljfp pushed a commit to ljfp/cpython that referenced this pull request Apr 25, 2026
@pablogsal @ljfp
pythongh-144727: Add test for circular lazy import crash (python#144727…
c75f9bd
…) (python#144838)

Add a regression test ensuring that circular lazy imports raise a proper
error (ImportCycleError) instead of crashing with a segfault. The crash
was fixed in pythongh-144733 but no test was added at the time.
@pablogsal
pablogsal deleted the lazy-cleanup-2 branch September 24, 2026 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Yhg1s Yhg1s Yhg1s approved these changes
@kumaraditya303 kumaraditya303 kumaraditya303 approved these changes
@brettcannon brettcannon Awaiting requested review from brettcannon
@DinoV DinoV Awaiting requested review from DinoV
@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently
@ncoghlan ncoghlan Awaiting requested review from ncoghlan
@warsaw warsaw Awaiting requested review from warsaw

Uh oh!

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

Assignees

No one assigned

Labels

skip news

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.

3 participants

@pablogsal @Yhg1s @kumaraditya303
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.