python / python/cpython

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

Aberta
#157,741 3 comentários 0 reações 0 responsáveis Ver no GitHub

Ninguém assumiu esta issue ainda.

3.15 extension-modules type-crash
Linguagem predominante
Python
Estrelas
77.2k
Forks
36k
Métricas de merge de PRs
Métricas de PR pendentes

Descrição

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

Guia de contribuição

Abrir o guia de contribuição

Primeiros passos

  1. Leia a issue inteira e depois o guia de contribuição do projeto.
  2. Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
  3. Faça um fork do repositório e trabalhe em uma branch.
  4. Abra um pull request que referencie o número da issue.

Direção de pesquisa

Comece reproduzindo o crash com min.py e, em seguida, inspecione o caminho de os.environ.clear() por meio de posix._clearenv(). Verifique o comportamento em torno do ponteiro environ de C e execute os testes relevantes de ambiente e tkinter; o trabalho estará concluído quando limpar os.environ não fizer mais tkinter.Tcl() travar na plataforma afetada.

Escrita pelo modelo de indexação a partir do texto da issue.

Avaliação

Stack de tecnologia
c, python
Domínio
operating-systems
Tipo de issue
Bug
Dificuldade
4/5
Tempo estimado
3-5 dias
Status de atividade
Estagnada
Clareza
Claramente especificada
Facilidade para iniciantes
20/100

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.