-
Notifications
You must be signed in to change notification settings - Fork 27
FIX: Resource cleanup on Python shutdown to avoid segfaults #255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FIX: Resource cleanup on Python shutdown to avoid segfaults #255
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR addresses critical stability issues by implementing proper Python shutdown detection and resource cleanup in the native extension code to prevent segmentation faults during interpreter shutdown after SQL errors.
- Added Python shutdown/finalization state checks in the LOG function and SqlHandle::free method to avoid unsafe API calls during cleanup
- Enhanced exception handling to silently ignore errors when Python is in an inconsistent state
- Added comprehensive tests to verify that SQL syntax errors don't cause segfaults during Python shutdown
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| mssql_python/pybind/ddbc_bindings.cpp | Enhanced LOG function and SqlHandle::free method with Python shutdown detection and safe cleanup logic |
| tests/test_005_connection_cursor_lifecycle.py | Added new test cases to verify SQL syntax errors don't cause segfaults during Python shutdown scenarios |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
… bewithgaurav/fix_segfault_cleanup_sql_failures
📊 Code Coverage Report
Diff CoverageDiff: main...HEAD, staged and unstaged changes
Summary
mssql_python/pybind/ddbc_bindings.cppLines 677-697 677 py::object sys_module = py::module_::import("sys");
678 if (!sys_module.is_none()) {
679 // Check if the attribute exists before accessing it (for Python version compatibility)
680 if (py::hasattr(sys_module, "_is_finalizing")) {
! 681 py::object finalizing_func = sys_module.attr("_is_finalizing");
! 682 if (!finalizing_func.is_none() && finalizing_func().cast<bool>()) {
! 683 return true; // Python is finalizing
! 684 }
! 685 }
686 }
687 return false;
688 } catch (...) {
! 689 std::cerr << "Error occurred while checking Python finalization state." << std::endl;
690 // Be conservative - don't assume shutdown on any exception
691 // Only return true if we're absolutely certain Python is shutting down
! 692 return false;
! 693 }
694 }
695
696 // TODO: Revisit GIL considerations if we're using python's logger
697 template <typename... Args>Lines 706-732 706
707 py::object logger = py::module_::import("mssql_python.logging_config").attr("get_logger")();
708 if (py::isinstance<py::none>(logger)) return;
709
! 710 try {
! 711 std::string ddbcFormatString = "[DDBC Bindings log] " + formatString;
! 712 if constexpr (sizeof...(args) == 0) {
! 713 logger.attr("debug")(py::str(ddbcFormatString));
! 714 } else {
! 715 py::str message = py::str(ddbcFormatString).format(std::forward<Args>(args)...);
! 716 logger.attr("debug")(message);
! 717 }
! 718 } catch (const std::exception& e) {
! 719 std::cerr << "Logging error: " << e.what() << std::endl;
720 }
! 721 } catch (const py::error_already_set& e) {
722 // Python is shutting down or in an inconsistent state, silently ignore
! 723 (void)e; // Suppress unused variable warning
! 724 return;
725 } catch (const std::exception& e) {
726 // Any other error, ignore to prevent crash during cleanup
! 727 (void)e; // Suppress unused variable warning
! 728 return;
729 }
730 }
731
732 // TODO: Add more nuanced exception classes📋 Files Needing Attention📉 Files with overall lowest coverage (click to expand)mssql_python.pybind.connection.connection.cpp: 67.6%
mssql_python.ddbc_bindings.py: 68.5%
mssql_python.pybind.ddbc_bindings.cpp: 69.3%
mssql_python.cursor.py: 79.6%
mssql_python.connection.py: 81.7%
mssql_python.helpers.py: 84.7%
mssql_python.auth.py: 85.3%
mssql_python.type.py: 86.8%
mssql_python.pooling.py: 88.8%
mssql_python.exceptions.py: 90.4%🔗 Quick Links
|
sumitmsft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a comment
…s://github.com/microsoft/mssql-python into bewithgaurav/fix_segfault_cleanup_sql_failures
… bewithgaurav/fix_segfault_cleanup_sql_failures
sumitmsft
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Approved
Work Item / Issue Reference
Summary
This pull request addresses a critical segfault issue that occurred during Python interpreter shutdown when using the
mssql_pythonpackage, especially in scenarios with unclosed cursors, syntax errors, or concurrent operations. The changes introduce robust detection of Python's shutdown state to prevent unsafe resource cleanup and improve test coverage for these edge cases.Key changes include:
Python Shutdown Safety & Resource Cleanup
is_python_finalizing()inddbc_bindings.cppto reliably detect when Python is shutting down or finalizing, using bothPy_IsInitialized()and thesys._is_finalizingattribute for compatibility across Python versions.LOGfunction to skip logging if Python is shutting down, and to handle exceptions gracefully to avoid crashes during interpreter cleanup. [1] [2]SqlHandle::free()method to prevent freeingSQL_HANDLE_STMThandles during shutdown, as their parent DBC handles may already be freed, avoiding double-free and segfaults. Handles are marked as freed instead.Test Coverage for Shutdown and Concurrency Edge Cases
test_005_connection_cursor_lifecycle.pyto ensure no segfaults occur during Python shutdown, including:These changes significantly improve the stability of the
mssql_pythonpackage in complex and error-prone scenarios, especially during interpreter shutdown and multithreaded usage.