python / python/cpython

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

Aperta
#157,741 3 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

3.15 extension-modules type-crash
Lingua principale
Python
Stelle
77.2k
Fork
35.9k
Metriche di merge delle PR
Metriche PR in attesa

Descrizione

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

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Direzione di ricerca

Inizia riproducendo il crash con min.py, quindi esamina il percorso di os.environ.clear() attraverso posix._clearenv(). Verifica il comportamento relativo al puntatore environ di C ed esegui i test pertinenti dell’ambiente e di tkinter; il lavoro è completo quando la cancellazione di os.environ non causa più il crash di tkinter.Tcl() sulla piattaforma interessata.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
c, python
Ambito
operating-systems
Tipo di issue
Bug
Difficoltà
4/5
Tempo stimato
3-5 giorni
Stato di attività
Ferma
Chiarezza
Specificata chiaramente
Idoneità per principianti
20/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.