python / python/cpython

`os.environ.clear()` now leaves the C `environ` pointer NULL, which crashes Tcl/Tk (tkinter) on the next `Tcl_CreateInterp`

Offen
#157,741 3 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

3.15 extension-modules type-crash
Vorherrschende Sprache
Python
Sterne
77.2k
Forks
35.9k
PR-Merge-Kennzahlen
PR-Kennzahlen ausstehend

Beschreibung

Crash report

What happened?

Since gh-139482 (PR gh-139965, October 2025) os.environ.clear() calls posix._clearenv()
clearenv(3). On glibc clearenv() sets the global environ to NULL rather than to an
empty array. Any C library that walks environ without a NULL check then segfaults; Tcl is one
of them (TclSetupEnv in generic/tclEnv.c reads environ[0], in 8.6 and on Tcl main).
Before this change clear() removed keys one at a time with unsetenv(), which leaves
environ a valid empty array, and the program below worked.

The following code:

import os
os.environ.clear()
import tkinter
tkinter.Tcl()

Resulted in this output:

AddressSanitizer:DEADLYSIGNAL
==1527921==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x75e7d758a13f bp 0x78b7d9e5f060 sp 0x7ffdab0f82c0 T0)
==1527921==The signal is caused by a READ memory access.
==1527921==Hint: address points to the zero page.
    #0 0x75e7d758a13f in TclSetupEnv (/lib/x86_64-linux-gnu/libtcl8.6.so+0xb213f)
    #1 0x75e7d75114d8 in Tcl_CreateInterp (/lib/x86_64-linux-gnu/libtcl8.6.so+0x394d8)
    #2 0x75e7d88c1607 in Tkapp_New Modules/_tkinter.c:643:17
    #3 0x75e7d88c1607 in _tkinter_create_impl Modules/_tkinter.c:3483:25
    #4 0x75e7d88c1607 in _tkinter_create Modules/clinic/_tkinter.c.h:898:20
    #5 0x6375e0068750 in cfunction_vectorcall_FASTCALL Objects/methodobject.c:449:24
    #6 0x6375dfeb5205 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:144:11
    #7 0x6375e04005ac in _Py_VectorCallInstrumentation_StackRefSteal Python/ceval.c:770:11
    #8 0x6375e0449521 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1906:35
    #9 0x6375e03ff857 in _PyEval_Vector Python/ceval.c:2176:12
    #10 0x6375dfeb55b4 in _PyObject_VectorcallDictTstate Objects/call.c:135:15
    #11 0x6375dfeb97e6 in _PyObject_Call_Prepend Objects/call.c:504:24
    #12 0x6375e017d7b0 in call_method Objects/typeobject.c:3070:19
    #13 0x6375e01c9165 in slot_tp_init Objects/typeobject.c:11115:21
    #14 0x6375e0159c7a in type_call Objects/typeobject.c:2454:19

Without a sanitizer it is a plain Segmentation fault. It is deterministic.

Evidence that the NULL pointer is the cause:

import os, ctypes
environ = ctypes.c_void_p.in_dll(ctypes.CDLL(None), "environ")
os.environ.clear()
print(environ.value)          # None  -> environ == NULL

Deleting the keys individually instead keeps environ non-NULL and tkinter.Tcl() succeeds:

import os
for k in list(os.environ):
    del os.environ[k]
import tkinter
tkinter.Tcl()                 # OK

Calling libc.clearenv() directly from ctypes reproduces the crash too, so the library
behaviour is glibc's; the regression is that os.environ.clear() now exposes it to every
tkinter (and any other environ-walking extension) user. Possible fixes on the CPython side:
after clearenv(), point environ at a static {NULL} array (glibc's setenv/putenv copy
rather than realloc an environ they did not allocate, so this is safe), or fall back to the
per-key unsetenv() loop.

To reproduce:

./python min.py

Commit:

e682b4478c2ad09de0bbe821127f451f02f6e5ca  (main, 2026-09-16)

Build configuration:

../configure --with-pydebug --enable-experimental-jit=yes --with-address-sanitizer --with-undefined-behavior-sanitizer

Operating System:

Ubuntu 22.04.5 LTS, x86_64, glibc 2.35, Tcl/Tk 8.6.12 (libtcl8.6 8.6.12+dfsg-1build1), in Docker (image fusion-fuzz-cpython:latest)

This bug was found by fusion-fuzz

CPython versions tested on:

CPython main branch

Operating systems tested on:

No response

Output from running 'python -VV' on the command line:

No response

Linked PRs
  • gh-157745

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginne damit, den Absturz mit min.py zu reproduzieren, und untersuche dann den Pfad os.environ.clear() über posix._clearenv(). Überprüfe das Verhalten rund um den C-environ-Zeiger und führe die relevanten Tests für die Umgebung und tkinter aus; abgeschlossen ist die Aufgabe, wenn das Leeren von os.environ tkinter.Tcl() auf der betroffenen Plattform nicht mehr zum Absturz bringt.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
c, python
Bereich
operating-systems
Issue-Typ
Bug
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Veraltet
Klarheit
Klar beschrieben
Anfängerfreundlichkeit
20/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.