duckdb / duckdb/duckdb-python

Crash when terminating process if Py_Finalize isn't called

Abierto
#531 1 comentario 0 reacciones 0 asignados Ver en GitHub
needs triage
Lenguaje dominante
Python
Estrellas
187
Forks
112
Merge medio
13 h 29 min
PR fusionados (30 d)
17

Descripción

### What happens?

If Python is embedded in another application and the process terminates without a chance for Py_Finalize to be called, there's a DuckDBPyConnection object that gets destroyed by the C runtime when the process ends, and that causes the process to crash.

In ~DuckDBPyConnection it's assumed the GIL is already held, but this isn't true when the process is being terminated (gil_scoped_release calls PyEval_SaveThread, and PyEval_SaveThread crashes because the GIL is not held). This object is cleaned up if Py_Finalize is called via a capsule, but that shouldn't be relied on.

A quick fix would be to add Py_IsInitialized and PyGILState_Check checks to ~DuckDBPyConnection, but a better fix would be to not do this cleanup in the destructor of a static and instead to move this to module state so Python can manage its lifecycle. I see there's a comment about PEP 489 already in the code suggesting the same.

### To Reproduce

```
# Importing duckdb is enough to cause this script to crash.
# Comment this line out and it will work fine.
import duckdb

import ctypes

# ctypes releases the GIL around this call (standard behavior for foreign DLL calls,
# unlike ctypes.pythonapi calls). ExitProcess never returns, so the GIL stays released
# from here on - (no Python code running, GIL not held).
# Py_Finalize is never called. ExitProcess still triggers DLL_PROCESS_DETACH for every
# loaded DLL, so _duckdb.pyd's static destructor runs with no GIL held and no valid
# thread state for this thread.
ctypes.windll.kernel32.ExitProcess(0)
```

### OS:

Windows

### DuckDB Package Version:

1.5.4

### Python Version:

3.14.5

### Full Name:

Tony Roberts

### Affiliation:

PyXLL Ltd

### What is the latest build you tested with? If possible, we recommend testing with the latest nightly build.

I have tested with a source build

### Did you include all relevant data sets for reproducing the issue?

Not applicable - the reproduction does not require a data set

### Did you include all code required to reproduce the issue?

- [x] Yes, I have

### Did you include all relevant configuration to reproduce the issue?

- [x] Yes, I have

Guía de contribución

Abrir la guía de contribución

Línea de trabajo

Comienza con el comportamiento del destructor de DuckDBPyConnection y de Py_Finalize y PyGILState_Check descrito en el informe; después revisa el comentario existente sobre PEP 489. Usa la reproducción proporcionada con Windows ctypes.ExitProcess; se considera terminado cuando importar duckdb y terminar sin Py_Finalize ya no provoca un fallo.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c, python
Área
backend-api-design
Tipo de issue
Error
Dificultad
4/5
Tiempo estimado
3-5 días
Estado de actividad
Activo
Claridad
Bastante claro
Aptitud para principiantes
45/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.