-
Notifications
You must be signed in to change notification settings - Fork 27
FIX: Access Token Handling, Shutdown Safety, and Connection Attribute Tests #266
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
base: main
Are you sure you want to change the base?
Changes from 19 commits
b3bf2a7
877d4b4
ef2f9ee
0990476
0694bb2
55f3349
a1b8b05
1048227
4f48b68
9623ed8
8298689
aaf3d85
aaa1da0
94fafc5
3d312ec
1cd6324
a2d1f0e
f57da1d
4cb300d
c118217
e412a4a
e624c13
2ebc7c1
40bce3f
e67a21d
7f6379b
27e6043
11f0b5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,16 +173,25 @@ SQLRETURN Connection::setAttribute(SQLINTEGER attribute, py::object value) { | |
| LOG("Setting SQL attribute"); | ||
| SQLPOINTER ptr = nullptr; | ||
| SQLINTEGER length = 0; | ||
| std::string buffer; // to hold sensitive data temporarily | ||
|
|
||
| if (py::isinstance<py::int_>(value)) { | ||
| int intValue = value.cast<int>(); | ||
| ptr = reinterpret_cast<SQLPOINTER>(static_cast<uintptr_t>(intValue)); | ||
| length = SQL_IS_INTEGER; | ||
| } else if (py::isinstance<py::bytes>(value) || py::isinstance<py::bytearray>(value)) { | ||
| static std::vector<std::string> buffers; | ||
| buffers.emplace_back(value.cast<std::string>()); | ||
| ptr = const_cast<char*>(buffers.back().c_str()); | ||
| length = static_cast<SQLINTEGER>(buffers.back().size()); | ||
| buffer = value.cast<std::string>(); // stack buffer | ||
|
|
||
| // DEFENSIVE FIX: Protect against ODBC driver bug with short access tokens | ||
| // Microsoft ODBC Driver 18 crashes when given access tokens shorter than 32 bytes | ||
| // Real access tokens are typically 100+ bytes, so reject anything under 32 bytes | ||
| if (attribute == SQL_COPT_SS_ACCESS_TOKEN && buffer.size() < 32) { | ||
| LOG("Access token too short (< 32 bytes) - protecting against ODBC driver crash"); | ||
| return SQL_ERROR; // Return error instead of letting ODBC crash | ||
| } | ||
|
Comment on lines
188
to
191
|
||
|
|
||
| ptr = buffer.data(); | ||
| length = static_cast<SQLINTEGER>(buffer.size()); | ||
| } else { | ||
| LOG("Unsupported attribute value type"); | ||
| return SQL_ERROR; | ||
|
|
@@ -195,6 +204,11 @@ SQLRETURN Connection::setAttribute(SQLINTEGER attribute, py::object value) { | |
| else { | ||
| LOG("Set attribute successfully"); | ||
| } | ||
|
|
||
| // Zero out sensitive data if used | ||
| if (!buffer.empty()) { | ||
| std::fill(buffer.begin(), buffer.end(), static_cast<char>(0)); | ||
| } | ||
| return ret; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -665,24 +665,67 @@ void HandleZeroColumnSizeAtFetch(SQLULEN& columnSize) { | |||||||||||||||||||
|
|
||||||||||||||||||||
| } // namespace | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // Helper function to check if Python is shutting down or finalizing | ||||||||||||||||||||
| // This centralizes the shutdown detection logic to avoid code duplication | ||||||||||||||||||||
| static bool is_python_finalizing() { | ||||||||||||||||||||
| try { | ||||||||||||||||||||
| if (Py_IsInitialized() == 0) { | ||||||||||||||||||||
| return true; // Python is already shut down | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| py::gil_scoped_acquire gil; | ||||||||||||||||||||
| py::object sys_module = py::module_::import("sys"); | ||||||||||||||||||||
| if (!sys_module.is_none()) { | ||||||||||||||||||||
| // Check if the attribute exists before accessing it (for Python version compatibility) | ||||||||||||||||||||
| if (py::hasattr(sys_module, "_is_finalizing")) { | ||||||||||||||||||||
| py::object finalizing_func = sys_module.attr("_is_finalizing"); | ||||||||||||||||||||
| if (!finalizing_func.is_none() && finalizing_func().cast<bool>()) { | ||||||||||||||||||||
| return true; // Python is finalizing | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| } | ||||||||||||||||||||
| return false; | ||||||||||||||||||||
| } catch (...) { | ||||||||||||||||||||
| std::cerr << "Error occurred while checking Python finalization state." << std::endl; | ||||||||||||||||||||
|
Comment on lines
688
to
689
|
||||||||||||||||||||
| } catch (...) { | |
| std::cerr << "Error occurred while checking Python finalization state." << std::endl; | |
| } catch (const std::exception& e) { | |
| std::cerr << "Error occurred while checking Python finalization state: " << e.what() << std::endl; | |
| // Be conservative - don't assume shutdown on any exception | |
| // Only return true if we're absolutely certain Python is shutting down | |
| return false; | |
| } catch (...) { | |
| std::cerr << "Unknown error occurred while checking Python finalization state." << std::endl; |
Uh oh!
There was an error while loading. Please reload this page.