public inbox for [email protected]
help / color / mirror / Atom feedFrom: Andrey Sukhanov <[email protected]>
To: [email protected]
Subject: psqlodbc crashes while collecting diagnostic records with SQLGetDiagRecW
Date: Thu, 22 Feb 2024 13:29:35 +0700
Message-ID: <[email protected]> (raw)
Dear pgsql-odbc developers,
Windows 10, psqlodbc 16 (psqlodbc35w.dll), postgresql 11.
Getting certain amount of diagnostic records with SQLGetDiagRecW crashes
the application with memory access violation.
Steps to reproduce:
1. Create procedure:
CREATE OR REPLACE PROCEDURE crashme()
LANGUAGE plpgsql
AS $$
BEGIN
FOR i IN 1..841 LOOP
RAISE NOTICE 'msgmsgmsgmsg (%)', i;
END LOOP;
END; $$;
2. Use example code in attachments.
3. Application crashes with memory access violation after calling
SQLGetDiagRecW function, with iRecord = 332.
Application doesn't crash if number of iterations in procedure's for
loop is changed.
Expected outcome: SQLGetDiagRecW would return SQL_NO_DATA when there's
no more diagnostic records.
Regards,
Andrey
Attachments:
[text/x-c++src] sqlgetdiagrec_crash.cpp (3.4K, 2-sqlgetdiagrec_crash.cpp)
download | inline:
#include <iostream>
#include <memory>
#include <string>
#include <sql.h>
#include <sqlext.h>
// Collects diagnostic records without without saving until SQL_NO_DATA.
void CollectDiagRecords(SQLSMALLINT hndlType, SQLHANDLE hndl)
{
constexpr size_t msgBufferSize = 100;
SQLINTEGER error;
SQLSMALLINT msgSize{ 0 };
SQLWCHAR msgBuffer[msgBufferSize];
SQLWCHAR state[SQL_SQLSTATE_SIZE + 1];
for(SQLSMALLINT index = 1; ; ++index)
{
// Crashes after calling this function with index == 332. It is dependant on msgBufferSize and SQL procedure.
auto diagRet = SQLGetDiagRec(
hndlType,
hndl,
index,
state,
&error,
msgBuffer,
(SQLSMALLINT)msgBufferSize,
&msgSize);
switch(diagRet)
{
case SQL_SUCCESS:
//BOOST_LOG_TRIVIAL(info) << index << " " << boost::locale::conv::utf_to_utf<char>(state, state + SQL_SQLSTATE_SIZE) << " " << boost::locale::conv::utf_to_utf<char>(msgBuffer, msgBuffer + msgSize) << std::endl;
continue;
case SQL_SUCCESS_WITH_INFO:
{
auto bufferSize = msgSize + 1;
std::unique_ptr< SQLWCHAR[] > buf{ new SQLWCHAR[bufferSize] };
SQLGetDiagRec(hndlType, hndl, index, state, &error, buf.get(), bufferSize, &msgSize);
}
continue;
case SQL_INVALID_HANDLE:
throw std::runtime_error("CollectDiagRecords SQL_INVALID_HANDLE");
case SQL_ERROR:
throw std::runtime_error("CollectDiagRecords SQL_ERROR");
case SQL_NO_DATA:
// End collecting diag info
return;
}
}
}
int main(int argc, char** argv)
{
try
{
SQLHDBC hdbc = nullptr;
SQLHENV henv = nullptr;
// Allocate environment handle
auto ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
throw std::runtime_error("SQLAllocHandle SQL_HANDLE_ENV");
}
SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);
// Allocate connection handle
ret = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);
if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
CollectDiagRecords(SQL_HANDLE_ENV, henv);
throw std::runtime_error("SQLAllocHandle SQL_HANDLE_DBC");
}
// Connect
SQLWCHAR connString[] = L"Driver={PostgreSQL Unicode(x64)};Server=127.0.0.1;Port=5433;Database=crashdb;Uid=user1;Pwd=user1;";
ret = SQLDriverConnect(hdbc, nullptr, connString, sizeof(connString)/sizeof(SQLWCHAR), nullptr, 0, nullptr, SQL_DRIVER_NOPROMPT);
if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
CollectDiagRecords(SQL_HANDLE_DBC, hdbc);
throw std::runtime_error("SQLDriverConnect");
}
SQLHSTMT hstmt;
ret = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);
if(ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO)
{
throw std::runtime_error("SQLAllocHandle SQL_HANDLE_STMT");
}
SQLWCHAR query[] = L"CALL public.crashme()";
ret = SQLExecDirect(hstmt, query, sizeof(query)/sizeof(SQLWCHAR));
switch(ret)
{
case SQL_SUCCESS:
break;
case SQL_SUCCESS_WITH_INFO:
// SQL Procedure crashme() returns "NOTICE" messages, which causes SQLExecDirect return SQL_SUCCESS_WITH_INFO.
CollectDiagRecords(SQL_HANDLE_STMT, hstmt);
break;
default:
throw std::runtime_error("SQLExecDirect default");
}
SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
SQLDisconnect(hdbc);
SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
SQLFreeHandle(SQL_HANDLE_ENV, henv);
}
catch(std::exception& e)
{
std::cerr << e.what() << std::endl;
return -1;
}
return 0;
}
view thread (6+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected]
Subject: Re: psqlodbc crashes while collecting diagnostic records with SQLGetDiagRecW
In-Reply-To: <[email protected]>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox