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".
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".