|
6 | 6 | #include "logger_bridge.hpp" |
7 | 7 | #include <pybind11/embed.h> |
8 | 8 | #include <algorithm> |
9 | | -#include <cstring> |
| 9 | +#include <array> |
10 | 10 | #include <functional> |
11 | 11 | #include <iostream> |
12 | 12 | #include <unordered_map> |
@@ -166,10 +166,17 @@ SQLRETURN SQL_API disconnect(SQLHDBC dbc) { |
166 | 166 | } |
167 | 167 |
|
168 | 168 | SQLRETURN SQL_API getInfo(SQLHDBC dbc, SQLUSMALLINT, SQLPOINTER value, |
169 | | - SQLSMALLINT, SQLSMALLINT* length) { |
170 | | - *length = sizeof(dbc); |
| 169 | + SQLSMALLINT bufferLength, SQLSMALLINT* length) { |
| 170 | + const auto required = static_cast<SQLSMALLINT>(sizeof(dbc)); |
| 171 | + if (length) { |
| 172 | + *length = required; |
| 173 | + } |
| 174 | + if (bufferLength < 0 || (value && bufferLength < required)) { |
| 175 | + return SQL_ERROR; |
| 176 | + } |
171 | 177 | if (value) { |
172 | | - std::memcpy(value, &dbc, sizeof(dbc)); |
| 178 | + std::copy_n(reinterpret_cast<const unsigned char*>(&dbc), sizeof(dbc), |
| 179 | + static_cast<unsigned char*>(value)); |
173 | 180 | } |
174 | 181 | return SQL_SUCCESS; |
175 | 182 | } |
@@ -383,6 +390,46 @@ int main() { |
383 | 390 | std::cout << "PASS " << name << '\n'; |
384 | 391 | }; |
385 | 392 | try { |
| 393 | + run("getInfo size queries allow null output and length pointers", [] { |
| 394 | + Handle handle{SQL_HANDLE_DBC, nullptr}; |
| 395 | + SQLSMALLINT length = 0; |
| 396 | + require(getInfo(&handle, SQL_DRIVER_HDBC, nullptr, 0, &length) == SQL_SUCCESS, |
| 397 | + "Size query failed"); |
| 398 | + require(length == static_cast<SQLSMALLINT>(sizeof(SQLHDBC)), |
| 399 | + "Size query returned the wrong handle size"); |
| 400 | + require(getInfo(&handle, SQL_DRIVER_HDBC, nullptr, 0, nullptr) == SQL_SUCCESS, |
| 401 | + "Optional length pointer was dereferenced"); |
| 402 | + }); |
| 403 | + run("getInfo rejects short buffers without writing", [] { |
| 404 | + Handle handle{SQL_HANDLE_DBC, nullptr}; |
| 405 | + std::array<unsigned char, sizeof(SQLHDBC)> buffer; |
| 406 | + for (SQLSMALLINT capacity = -1; |
| 407 | + capacity < static_cast<SQLSMALLINT>(buffer.size()); ++capacity) { |
| 408 | + buffer.fill(0xa5); |
| 409 | + SQLSMALLINT length = 0; |
| 410 | + require(getInfo(&handle, SQL_DRIVER_HDBC, buffer.data(), capacity, &length) == SQL_ERROR, |
| 411 | + "Short buffer was accepted"); |
| 412 | + require(length == static_cast<SQLSMALLINT>(sizeof(SQLHDBC)), |
| 413 | + "Short buffer did not report the required size"); |
| 414 | + require(std::all_of(buffer.begin(), buffer.end(), |
| 415 | + [](unsigned char byte) { return byte == 0xa5; }), |
| 416 | + "Short buffer was modified"); |
| 417 | + } |
| 418 | + }); |
| 419 | + run("getInfo copies handle bytes into an unaligned exact-size buffer", [] { |
| 420 | + Handle handle{SQL_HANDLE_DBC, nullptr}; |
| 421 | + SQLHDBC dbc = &handle; |
| 422 | + alignas(SQLHDBC) std::array<unsigned char, sizeof(SQLHDBC) + 2> buffer; |
| 423 | + buffer.fill(0xa5); |
| 424 | + require(getInfo(dbc, SQL_DRIVER_HDBC, buffer.data() + 1, |
| 425 | + static_cast<SQLSMALLINT>(sizeof(dbc)), nullptr) == SQL_SUCCESS, |
| 426 | + "Exact-size buffer was rejected"); |
| 427 | + require(std::equal(buffer.begin() + 1, buffer.end() - 1, |
| 428 | + reinterpret_cast<const unsigned char*>(&dbc)), |
| 429 | + "Copied handle representation differs"); |
| 430 | + require(buffer.front() == 0xa5 && buffer.back() == 0xa5, |
| 431 | + "Copy wrote outside the advertised buffer"); |
| 432 | + }); |
386 | 433 | for (SQLRETURN origin : {SQLRETURN(SQL_SUCCESS_WITH_INFO), SQLRETURN(SQL_NO_DATA)}) { |
387 | 434 | run("successful zero-record header avoids enumeration without clearing messages", [origin] { |
388 | 435 | auto connection = acquire(); |
|
0 commit comments