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 — Concurrent codecs.unregister() calls can crash in PyCodec_Unregister · Issue #157078 · python/cpython

Concurrent codecs.unregister() calls can crash in PyCodec_Unregister #157078

New issue
Copy link
New issue
Copy link
Closed as not planned
Closed as not planned
Concurrent codecs.unregister() calls can crash in PyCodec_Unregister#157078
Copy link

Description

@Nievesjyl
Nievesjyl
opened on Sep 7, 2026
Issue body actions

Description

PyCodec_Unregister() reads PyList_GET_SIZE(codec_search_path) for its loop condition before acquiring search_path_mutex, then acquires the mutex and fetches index i with PyList_GetItemRef(). Another unregister call can shorten the list between those operations. The indexed fetch then returns NULL, but the function later calls Py_DECREF(item) unconditionally.

Observed Behavior

Eight threads repeatedly registering and unregistering one search function caused an ASan SEGV on address 0x0c in Py_DECREF() at Python/codecs.c:83 after 0.23 seconds. The same executable completed the four-second GIL-enabled control.

Affected Version

CPython 3.14.7 at commit 823f0323ee6ec1402088b73bce1a38473cac36dc, tested with a free-threaded ASan build.

Reproduction

ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 PYTHON_GIL=0 python3.14 poc/reproduce.py 10

Setting PYTHON_GIL=1 provides the GIL-enabled control.

PoC Source Code

poc/reproduce.py

import codecs
import sys
import threading
import time


duration = float(sys.argv[1]) if len(sys.argv) > 1 else 10.0
stop = threading.Event()


def search(name):
    return None


codecs.register(search)


def exercise():
    while not stop.is_set():
        codecs.unregister(search)
        codecs.register(search)


threads = [threading.Thread(target=exercise) for _ in range(8)]
for thread in threads:
    thread.start()
time.sleep(duration)
stop.set()
for thread in threads:
    thread.join()
print("completed")

Activity

  1. ZeroIntensity commented on Sep 7, 2026

    @ZeroIntensity
    ZeroIntensity
    on Sep 7, 2026
    Member
    More actions

    Refer to #157124 (comment)

  2. ZeroIntensity
    closed this as not plannedon Sep 7, 2026
  3. JelleZijlstra
    added 3 commits that reference this issue on Oct 22, 2026

    gh-159739: Hold the codec registry lock while unregistering (#160168)

    784b305

    [3.15] gh-159739: Hold the codec registry lock while unregistering (G…

    47667b8

    [3.14] gh-159739: Hold the codec registry lock while unregistering (G…

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      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.