Skip to content

Commit 27e2259

Browse files
sumitmsftCopilot
andcommitted
TEST: Bounds-check native getInfo fixture without memcpy
Replace the test-only raw copy with a validated portable byte copy and cover short, null, and unaligned buffers. No production driver changes or alert suppressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 205b491 commit 27e2259

1 file changed

Lines changed: 51 additions & 4 deletions

File tree

‎tests/native/pool_sanitation.cpp‎

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#include "logger_bridge.hpp"
77
#include <pybind11/embed.h>
88
#include <algorithm>
9-
#include <cstring>
9+
#include <array>
1010
#include <functional>
1111
#include <iostream>
1212
#include <unordered_map>
@@ -166,10 +166,17 @@ SQLRETURN SQL_API disconnect(SQLHDBC dbc) {
166166
}
167167

168168
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+
}
171177
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));
173180
}
174181
return SQL_SUCCESS;
175182
}
@@ -383,6 +390,46 @@ int main() {
383390
std::cout << "PASS " << name << '\n';
384391
};
385392
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+
});
386433
for (SQLRETURN origin : {SQLRETURN(SQL_SUCCESS_WITH_INFO), SQLRETURN(SQL_NO_DATA)}) {
387434
run("successful zero-record header avoids enumeration without clearing messages", [origin] {
388435
auto connection = acquire();

0 commit comments

Comments
 (0)