Bug #38396 C API: mysql_stmt_execute crash if called when the server is down
Description:
Calling mysql_stmt_execute may generate an Access Violation when called after the MySQL server has been shutdown or terminated.
The prepared statement is a INSERT into a table.
MySQL server and client library version 5.0.51b.
DLL version of the client library
Dev Env: Microsoft Visual Studio 6.0.
The complete project (Microsoft Visual Studio 6.0) to reproduce it is uploaded to FTP as bug-data-20087.zip
Here is the listing of main function:
extern "C" int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED);
_Module.Init(NULL, hInstance);
PCSTR pcszError = NULL;
MYSQL* pInitConn = ::mysql_init(NULL);
if (pInitConn != NULL)
{
// connect to localhost using anonymous account
// InnoDB is used by default
my_bool fTrue = true;
::mysql_options(pInitConn,MYSQL_OPT_RECONNECT,(PCSTR)&fTrue);
DWORD dwProtocol = MYSQL_PROTOCOL_TCP;
::mysql_options(pInitConn,MYSQL_OPT_PROTOCOL,(PCSTR)&dwProtocol);
::mysql_options(pInitConn,MYSQL_SET_CHARSET_NAME,(PCSTR)"cp1251");
PCSTR pcszURL = "127.0.0.1";
//PCSTR pcszURL = "192.168.0.104";
PCSTR pcszLogin = NULL;
PCSTR pcszPassword = NULL;
MYSQL* pDBConn = ::mysql_real_connect(pInitConn,pcszURL,pcszLogin,pcszPassword,NULL,3306,NULL,0);
if (pDBConn != NULL)
{
DWORD dwVersion = ::mysql_get_server_version(pDBConn);
// create and connect to MyCrashTest db
int nResult = ::mysql_query(pDBConn,"CREATE DATABASE IF NOT EXISTS MyCrashTest");
nResult = ::mysql_query(pDBConn,"USE MyCrashTest");
if (nResult == 0)
{
// create InsertTest table
nResult = ::mysql_query(pDBConn,"CREATE TABLE InsertTest(`ID` INT AUTO_INCREMENT PRIMARY KEY, `Value` INT UNSIGNED DEFAULT \"0\")");
// create prepared statement to insert data into InsertTest table
MYSQL_STMT* pStmt = ::mysql_stmt_init(pDBConn);
if (pStmt != NULL)
{
DWORD dwFields = 1;
MYSQL_BIND* pBind = new MYSQL_BIND[dwFields];
::ZeroMemory(pBind,sizeof(MYSQL_BIND) * dwFields);
DWORD dwLength = 4;
my_bool fIsNull = false;
DWORD dwValue = 0;
pBind[0].length = &dwLength;
pBind[0].is_null = &fIsNull;
pBind[0].is_unsigned = TRUE;
pBind[0].buffer = &dwValue;
pBind[0].buffer_length = 4;
pBind[0].buffer_type = MYSQL_TYPE_LONG;
PCSTR pcszQuery = "INSERT INTO InsertTest (`Value`) VALUES (?)";
int nPrepareRet = ::mysql_stmt_prepare(pStmt,pcszQuery,::lstrlen(pcszQuery));
if (nPrepareRet == 0)
{
if (::mysql_stmt_param_count(pStmt) == dwFields)
{
my_bool fBinded = ::mysql_stmt_bind_param(pStmt,pBind);
if (fBinded == 0)
{
// OK, now insert 3 values...
// server is still working
dwValue = ::GetTickCount();
int nExecuteRet = ::mysql_stmt_execute(pStmt);
// must be ok
// NOW STOP THE MYSQL PROCESS (KILL SERVER)
// server is stopped
::Sleep(500);
dwValue = ::GetTickCount();
nExecuteRet = ::mysql_stmt_execute(pStmt);
// must be error (Can't connect to MySQL server)
::Sleep(500);
dwValue = ::GetTickCount();
nExecuteRet = ::mysql_stmt_execute(pStmt);
// must be Access Violation (0xC0000005)
}
}
}
::mysql_stmt_close(pStmt);
delete[] pBind;
}
}
}
::mysql_close(pInitConn);
pInitConn = NULL;
}
_Module.Term();
CoUninitialize();
return 0;
}
How to repeat:
Have the server up and running and have the client app connect to the server and prepare an INSERT statement.
The connection is set with the OPT_RECONNECT.
While the app is executing the prepared statement (in a loop), shutdown the server.
The statement execution during fails in a controlled manner, the second or third execution of mysql_stmt_execute triggers an access violation exception.
Similar outcomes if the server is killed: the difference is that the first execution reports a failure condition of "Lost connection..." instead of "shutdown in progress".
Portions of this website are copyright © 2001, 2002 The PHP Group
Page generated in 0.050 sec. using MySQL 8.4.7-u6-cloud
Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the
respective copyright holders.
It is not reviewed in advance
by Oracle and does not necessarily represent the opinion of
Oracle or any other party.
Description: Calling mysql_stmt_execute may generate an Access Violation when called after the MySQL server has been shutdown or terminated. The prepared statement is a INSERT into a table. MySQL server and client library version 5.0.51b. DLL version of the client library Dev Env: Microsoft Visual Studio 6.0. The complete project (Microsoft Visual Studio 6.0) to reproduce it is uploaded to FTP as bug-data-20087.zip Here is the listing of main function: extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/) { lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT HRESULT hRes = CoInitializeEx(NULL, COINIT_MULTITHREADED); _Module.Init(NULL, hInstance); PCSTR pcszError = NULL; MYSQL* pInitConn = ::mysql_init(NULL); if (pInitConn != NULL) { // connect to localhost using anonymous account // InnoDB is used by default my_bool fTrue = true; ::mysql_options(pInitConn,MYSQL_OPT_RECONNECT,(PCSTR)&fTrue); DWORD dwProtocol = MYSQL_PROTOCOL_TCP; ::mysql_options(pInitConn,MYSQL_OPT_PROTOCOL,(PCSTR)&dwProtocol); ::mysql_options(pInitConn,MYSQL_SET_CHARSET_NAME,(PCSTR)"cp1251"); PCSTR pcszURL = "127.0.0.1"; //PCSTR pcszURL = "192.168.0.104"; PCSTR pcszLogin = NULL; PCSTR pcszPassword = NULL; MYSQL* pDBConn = ::mysql_real_connect(pInitConn,pcszURL,pcszLogin,pcszPassword,NULL,3306,NULL,0); if (pDBConn != NULL) { DWORD dwVersion = ::mysql_get_server_version(pDBConn); // create and connect to MyCrashTest db int nResult = ::mysql_query(pDBConn,"CREATE DATABASE IF NOT EXISTS MyCrashTest"); nResult = ::mysql_query(pDBConn,"USE MyCrashTest"); if (nResult == 0) { // create InsertTest table nResult = ::mysql_query(pDBConn,"CREATE TABLE InsertTest(`ID` INT AUTO_INCREMENT PRIMARY KEY, `Value` INT UNSIGNED DEFAULT \"0\")"); // create prepared statement to insert data into InsertTest table MYSQL_STMT* pStmt = ::mysql_stmt_init(pDBConn); if (pStmt != NULL) { DWORD dwFields = 1; MYSQL_BIND* pBind = new MYSQL_BIND[dwFields]; ::ZeroMemory(pBind,sizeof(MYSQL_BIND) * dwFields); DWORD dwLength = 4; my_bool fIsNull = false; DWORD dwValue = 0; pBind[0].length = &dwLength; pBind[0].is_null = &fIsNull; pBind[0].is_unsigned = TRUE; pBind[0].buffer = &dwValue; pBind[0].buffer_length = 4; pBind[0].buffer_type = MYSQL_TYPE_LONG; PCSTR pcszQuery = "INSERT INTO InsertTest (`Value`) VALUES (?)"; int nPrepareRet = ::mysql_stmt_prepare(pStmt,pcszQuery,::lstrlen(pcszQuery)); if (nPrepareRet == 0) { if (::mysql_stmt_param_count(pStmt) == dwFields) { my_bool fBinded = ::mysql_stmt_bind_param(pStmt,pBind); if (fBinded == 0) { // OK, now insert 3 values... // server is still working dwValue = ::GetTickCount(); int nExecuteRet = ::mysql_stmt_execute(pStmt); // must be ok // NOW STOP THE MYSQL PROCESS (KILL SERVER) // server is stopped ::Sleep(500); dwValue = ::GetTickCount(); nExecuteRet = ::mysql_stmt_execute(pStmt); // must be error (Can't connect to MySQL server) ::Sleep(500); dwValue = ::GetTickCount(); nExecuteRet = ::mysql_stmt_execute(pStmt); // must be Access Violation (0xC0000005) } } } ::mysql_stmt_close(pStmt); delete[] pBind; } } } ::mysql_close(pInitConn); pInitConn = NULL; } _Module.Term(); CoUninitialize(); return 0; } How to repeat: Have the server up and running and have the client app connect to the server and prepare an INSERT statement. The connection is set with the OPT_RECONNECT. While the app is executing the prepared statement (in a loop), shutdown the server. The statement execution during fails in a controlled manner, the second or third execution of mysql_stmt_execute triggers an access violation exception. Similar outcomes if the server is killed: the difference is that the first execution reports a failure condition of "Lost connection..." instead of "shutdown in progress".