-
Notifications
You must be signed in to change notification settings - Fork 25
Description
Describe the bug
Python segmentation fault occurs during interpreter shutdown when failed cursor operations are encountered. The crash happens when C++ destructors in the native extension try to call ODBC driver functions and Python logging APIs after Python has begun shutting down, causing invalid memory access and segfaults.
Exception details:
EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
Termination Reason: Namespace SIGNAL, Code 11 Segmentation fault: 11
Key stack trace elements:
...
2 ddbc_bindings.cp313-universal2.so SqlHandle::free() + 232
...
13 Python gc_collect_main + 2272
14 Python finalize_modules + 3048
15 Python _Py_Finalize + 936
To reproduce
Include a complete code listing (or project/solution) that we can run to reproduce the issue.
cursor = conn.cursor()
cursor.execute("syntax error") #Segfault happens here itself
row = cursor.fetchall()
print(row)
Expected behavior
The script should execute, catch the failed cursor operation, clean up resources properly, and exit without any segmentation fault. Python should shut down cleanly even after cursor operation failures occur.
Further technical details
Python version: 3.13
SQL Server version: SQL Server (any version with ODBC driver 18)
Operating system: macOS 14.7.1 (also reproducible on Linux)
Additional context
Root Cause Analysis:
The segmentation fault occurs during Python interpreter shutdown due to improper cleanup ordering:
- Python Shutdown Ordering: During
Py_Finalize()
, Python's garbage collector runs and finalizes C++ objects - Invalid Driver State: The ODBC driver library may be unloaded or become invalid during shutdown
- Python API Corruption:
sys.meta_path
becomesNone
during finalization, breaking import mechanisms - Destructor Calls: C++ destructors (
SqlHandle::free()
andLOG()
function) try to call Python APIs and ODBC functions after Python has begun shutting down
Technical Details:
- Crash occurs in
SqlHandle::free()
when callingSQLFreeHandle_ptr()
- Also affects
LOG()
function which tries to import Python modules during shutdown - The issue manifests as
EXC_BAD_ACCESS
at memory address0x0000000000000010
- Crash is triggered by failed cursor operations (SQL syntax errors, execution failures, etc.) that create objects requiring cleanup during interpreter shutdown
Workaround: Currently no reliable workaround exists, as the crash occurs during normal Python shutdown after any failed cursor operation.