Copilot commented on code in PR #49668:
URL: https://github.com/apache/arrow/pull/49668#discussion_r3089501546
##########
cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc:
##########
@@ -808,26 +835,28 @@ TYPED_TEST(ConnectionInfoTest,
TestSQLGetInfoInsertStatement) {
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoIntegrity) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_INTEGRITY, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_INTEGRITY, value);
- EXPECT_STREQ(static_cast<const SQLWCHAR*>(L"N"), value);
+ std::wstring result = ConvertToWString(value);
+ EXPECT_EQ(std::wstring(L"N"), result);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoKeywords) {
// Keyword strings can require 10000 buffer length
static constexpr int info_len = kOdbcBufferSize * 10;
- SQLWCHAR value[info_len] = L"";
- GetInfo(conn, SQL_KEYWORDS, value, info_len);
+ SQLWCHAR value[info_len] = {};
+ GetInfoSQLWCHAR(conn, SQL_KEYWORDS, value, info_len);
- EXPECT_GT(wcslen(value), 0);
+ EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
Review Comment:
Using wcslen(reinterpret_cast<wchar_t*>(value)) is undefined on platforms
where SQLWCHAR is not wchar_t (e.g., Linux with UTF-16 SQLWCHAR). This can read
past the buffer or compute an incorrect length. Prefer SqlWCharArrLen(value)
(or ConvertToWString(value).length()) for the non-empty assertion, especially
since this buffer can be much larger than kOdbcBufferSize.
```suggestion
EXPECT_GT(ConvertToWString(value).length(), 0U);
```
##########
cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc:
##########
@@ -382,40 +390,43 @@ TYPED_TEST(ConnectionInfoTest,
TestSQLGetInfoStaticCursorAttributes2) {
// DBMS Product Information
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDatabaseName) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_DATABASE_NAME, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_DATABASE_NAME, value);
- EXPECT_STREQ(static_cast<const SQLWCHAR*>(L""), value);
+ std::wstring result = ConvertToWString(value);
+ EXPECT_EQ(std::wstring(L""), result);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDbmsName) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_DBMS_NAME, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_DBMS_NAME, value);
- EXPECT_GT(wcslen(value), 0);
+ EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
}
Review Comment:
Using wcslen(reinterpret_cast<wchar_t*>(value)) is undefined on platforms
where SQLWCHAR is not wchar_t (e.g., Linux with UTF-16 SQLWCHAR). This can read
past the buffer or compute an incorrect length. Prefer SqlWCharArrLen(value) or
ConvertToWString(value).length() for the non-empty assertion.
##########
cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc:
##########
@@ -382,40 +390,43 @@ TYPED_TEST(ConnectionInfoTest,
TestSQLGetInfoStaticCursorAttributes2) {
// DBMS Product Information
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDatabaseName) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_DATABASE_NAME, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_DATABASE_NAME, value);
- EXPECT_STREQ(static_cast<const SQLWCHAR*>(L""), value);
+ std::wstring result = ConvertToWString(value);
+ EXPECT_EQ(std::wstring(L""), result);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDbmsName) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_DBMS_NAME, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_DBMS_NAME, value);
- EXPECT_GT(wcslen(value), 0);
+ EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoDbmsVer) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_DBMS_VER, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_DBMS_VER, value);
- EXPECT_GT(wcslen(value), 0);
+ EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
}
Review Comment:
Using wcslen(reinterpret_cast<wchar_t*>(value)) is undefined on platforms
where SQLWCHAR is not wchar_t (e.g., Linux with UTF-16 SQLWCHAR). This can read
past the buffer or compute an incorrect length. Prefer SqlWCharArrLen(value) or
ConvertToWString(value).length() for the non-empty assertion.
##########
cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc:
##########
@@ -491,7 +491,7 @@ bool WriteDSN(Connection::ConnPropertyMap properties) {
std::string driver = config.Get(FlightSqlConnection::DRIVER);
std::wstring w_driver = arrow::util::UTF8ToWideString(driver).ValueOr(L"");
- return RegisterDsn(config, w_driver.c_str());
+ return RegisterDsn(config, reinterpret_cast<LPCWSTR>(w_driver.c_str()));
}
Review Comment:
WriteDSN converts the driver name to std::wstring and then reinterpret_casts
w_driver.c_str() to LPCWSTR. On Linux, the driver manager expects UTF-16
SQLWCHAR (see system_dsn.cc ConvertToSQLWCHAR), so casting wchar_t* (UTF-32) to
LPCWSTR is likely incorrect and can mis-encode the driver name or cause
misaligned reads. Convert the UTF-8 driver string to the platform’s expected
SQLWCHAR representation before calling RegisterDsn (e.g., UTF8StringToUTF16 on
Linux, UTF8ToWideString elsewhere), and pass the resulting buffer pointer
without reinterpret_casting between incompatible character types.
##########
cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.h:
##########
@@ -38,6 +38,20 @@
// For DSN registration
#include "arrow/flight/sql/odbc/odbc_impl/system_dsn.h"
+#ifdef __linux__
+# define ASSIGN_SQLWCHAR_ARR(name, wstring_literal) \
+ auto name##_vec = ODBC::ToSqlWCharVector(std::wstring(wstring_literal)); \
+ SQLWCHAR* name = name##_vec.data();
+# define ASSIGN_SQLWCHAR_ARR_AND_LEN(name, wstring_literal) \
+ ASSIGN_SQLWCHAR_ARR(name, wstring_literal) \
+ size_t name##_len = std::wstring(wstring_literal).length();
+#else // Windows & Mac
+# define ASSIGN_SQLWCHAR_ARR(name, wstring_literal) SQLWCHAR name[] =
wstring_literal;
+# define ASSIGN_SQLWCHAR_ARR_AND_LEN(name, wstring_literal) \
+ ASSIGN_SQLWCHAR_ARR(name, wstring_literal) \
+ size_t name##_len = std::wcslen(name);
Review Comment:
On Linux, ASSIGN_SQLWCHAR_ARR builds a SQLWCHAR vector via
ODBC::ToSqlWCharVector but does not append a NUL terminator. Many call sites
pass SQL_NTS (and some helpers like ConvertToWString default to NTS), which can
lead to out-of-bounds reads in the driver manager/tests. Consider ensuring the
produced buffer is always NUL-terminated (e.g., append a 0 code unit) and base
any computed length on the converted buffer size (excluding the terminator)
rather than std::wstring(wstring_literal).length(). Also, defining the *_len
variable as an ODBC length type (SQLINTEGER/SQLSMALLINT as appropriate) will
avoid potential -Wshorten-64-to-32 warnings with Clang.
```suggestion
# define ASSIGN_SQLWCHAR_ARR(name, wstring_literal)
\
auto name##_vec = ODBC::ToSqlWCharVector(std::wstring(wstring_literal));
\
if (name##_vec.empty() || name##_vec.back() != static_cast<SQLWCHAR>(0))
{ \
name##_vec.push_back(static_cast<SQLWCHAR>(0));
\
}
\
SQLWCHAR* name = name##_vec.data();
# define ASSIGN_SQLWCHAR_ARR_AND_LEN(name, wstring_literal)
\
ASSIGN_SQLWCHAR_ARR(name, wstring_literal)
\
SQLINTEGER name##_len = static_cast<SQLINTEGER>(name##_vec.size() - 1);
#else // Windows & Mac
# define ASSIGN_SQLWCHAR_ARR(name, wstring_literal) SQLWCHAR name[] =
wstring_literal;
# define ASSIGN_SQLWCHAR_ARR_AND_LEN(name, wstring_literal) \
ASSIGN_SQLWCHAR_ARR(name, wstring_literal) \
SQLINTEGER name##_len = static_cast<SQLINTEGER>(std::wcslen(name));
```
##########
cpp/src/arrow/flight/sql/odbc/tests/statement_test.cc:
##########
@@ -1974,80 +1950,75 @@ TYPED_TEST(StatementTest,
TestSQLMoreResultsInvalidFunctionSequence) {
TYPED_TEST(StatementTest, TestSQLNativeSqlReturnsInputString) {
SQLWCHAR buf[1024];
SQLINTEGER buf_char_len = sizeof(buf) / GetSqlWCharSize();
- SQLWCHAR input_str[] = L"SELECT * FROM mytable WHERE id == 1";
- SQLINTEGER input_char_len = static_cast<SQLINTEGER>(wcslen(input_str));
+ ASSIGN_SQLWCHAR_ARR_AND_LEN(input_str, L"SELECT * FROM mytable WHERE id ==
1");
SQLINTEGER output_char_len = 0;
- std::wstring expected_string = std::wstring(input_str);
- ASSERT_EQ(SQL_SUCCESS, SQLNativeSql(conn, input_str, input_char_len, buf,
buf_char_len,
+ ASSERT_EQ(SQL_SUCCESS, SQLNativeSql(conn, input_str, input_str_len, buf,
buf_char_len,
&output_char_len));
- EXPECT_EQ(input_char_len, output_char_len);
+ EXPECT_EQ(input_str_len, output_char_len);
// returned length is in characters
std::wstring returned_string(buf, buf + output_char_len);
- EXPECT_EQ(expected_string, returned_string);
+ std::wstring input = ConvertToWString(input_str, input_str_len);
+ EXPECT_EQ(input, returned_string);
}
TYPED_TEST(StatementTest, TestSQLNativeSqlReturnsNTSInputString) {
SQLWCHAR buf[1024];
SQLINTEGER buf_char_len = sizeof(buf) / GetSqlWCharSize();
- SQLWCHAR input_str[] = L"SELECT * FROM mytable WHERE id == 1";
- SQLINTEGER input_char_len = static_cast<SQLINTEGER>(wcslen(input_str));
+ ASSIGN_SQLWCHAR_ARR_AND_LEN(input_str, L"SELECT * FROM mytable WHERE id ==
1");
SQLINTEGER output_char_len = 0;
- std::wstring expected_string = std::wstring(input_str);
ASSERT_EQ(SQL_SUCCESS,
SQLNativeSql(conn, input_str, SQL_NTS, buf, buf_char_len,
&output_char_len));
- EXPECT_EQ(input_char_len, output_char_len);
+ EXPECT_EQ(input_str_len, output_char_len);
// returned length is in characters
std::wstring returned_string(buf, buf + output_char_len);
+ std::wstring expected_string = ConvertToWString(input_str, input_str_len);
EXPECT_EQ(expected_string, returned_string);
}
TYPED_TEST(StatementTest, TestSQLNativeSqlReturnsInputStringLength) {
- SQLWCHAR input_str[] = L"SELECT * FROM mytable WHERE id == 1";
- SQLINTEGER input_char_len = static_cast<SQLINTEGER>(wcslen(input_str));
+ ASSIGN_SQLWCHAR_ARR_AND_LEN(input_str, L"SELECT * FROM mytable WHERE id ==
1");
SQLINTEGER output_char_len = 0;
- std::wstring expected_string = std::wstring(input_str);
ASSERT_EQ(SQL_SUCCESS,
- SQLNativeSql(conn, input_str, input_char_len, nullptr, 0,
&output_char_len));
+ SQLNativeSql(conn, input_str, input_str_len, nullptr, 0,
&output_char_len));
- EXPECT_EQ(input_char_len, output_char_len);
+ EXPECT_EQ(input_str_len, output_char_len);
ASSERT_EQ(SQL_SUCCESS,
SQLNativeSql(conn, input_str, SQL_NTS, nullptr, 0,
&output_char_len));
- EXPECT_EQ(input_char_len, output_char_len);
+ EXPECT_EQ(input_str_len, output_char_len);
}
TYPED_TEST(StatementTest, TestSQLNativeSqlReturnsTruncatedString) {
const SQLINTEGER small_buf_size_in_char = 11;
SQLWCHAR small_buf[small_buf_size_in_char];
SQLINTEGER small_buf_char_len = sizeof(small_buf) / GetSqlWCharSize();
- SQLWCHAR input_str[] = L"SELECT * FROM mytable WHERE id == 1";
- SQLINTEGER input_char_len = static_cast<SQLINTEGER>(wcslen(input_str));
+ ASSIGN_SQLWCHAR_ARR_AND_LEN(input_str, L"SELECT * FROM mytable WHERE id ==
1");
SQLINTEGER output_char_len = 0;
// Create expected return string based on buf size
SQLWCHAR expected_string_buf[small_buf_size_in_char];
- wcsncpy(expected_string_buf, input_str, 10);
+ wcsncpy(reinterpret_cast<wchar_t*>(expected_string_buf),
+ reinterpret_cast<const wchar_t*>(input_str), 10);
expected_string_buf[10] = L'\0';
Review Comment:
wcsncpy(reinterpret_cast<wchar_t*>(...)) is undefined when SQLWCHAR is not
wchar_t (notably on Linux where SQLWCHAR can be UTF-16). This can corrupt the
expected buffer and/or read misaligned memory. Instead, copy the first 10
SQLWCHAR code units using a type-safe approach (e.g., std::copy_n on SQLWCHAR)
and then explicitly write a SQLWCHAR NUL terminator.
##########
cpp/src/arrow/flight/sql/odbc/tests/connection_info_test.cc:
##########
@@ -345,24 +351,26 @@ TYPED_TEST(ConnectionInfoTest,
TestSQLGetInfoParamArraySelects) {
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoRowUpdates) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_ROW_UPDATES, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_ROW_UPDATES, value);
- EXPECT_STREQ(static_cast<const SQLWCHAR*>(L"N"), value);
+ std::wstring result = ConvertToWString(value);
+ EXPECT_EQ(std::wstring(L"N"), result);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoSearchPatternEscape) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_SEARCH_PATTERN_ESCAPE, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_SEARCH_PATTERN_ESCAPE, value);
- EXPECT_STREQ(static_cast<const SQLWCHAR*>(L"\\"), value);
+ std::wstring result = ConvertToWString(value);
+ EXPECT_EQ(std::wstring(L"\\"), result);
}
TYPED_TEST(ConnectionInfoTest, TestSQLGetInfoServerName) {
- SQLWCHAR value[kOdbcBufferSize] = L"";
- GetInfo(conn, SQL_SERVER_NAME, value);
+ SQLWCHAR value[kOdbcBufferSize] = {};
+ GetInfoSQLWCHAR(conn, SQL_SERVER_NAME, value);
- EXPECT_GT(wcslen(value), 0);
+ EXPECT_GT(wcslen(reinterpret_cast<wchar_t*>(value)), 0);
Review Comment:
Using wcslen(reinterpret_cast<wchar_t*>(value)) is undefined on platforms
where SQLWCHAR is not wchar_t (e.g., Linux with UTF-16 SQLWCHAR). This can read
past the buffer or compute an incorrect length. Prefer SqlWCharArrLen(value) or
ConvertToWString(value).length() for the non-empty assertion.
```suggestion
std::wstring result = ConvertToWString(value);
EXPECT_GT(result.length(), 0);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]