You've already forked mariadb-connector-c
mirror of
https://github.com/mariadb-corporation/mariadb-connector-c.git
synced 2025-08-08 14:02:17 +03:00
Fix for CONC-71: mysql_real_query crashes after server restart
- We now check socket status before net_flush (and return error if the socket is dead)
This commit is contained in:
@@ -21,12 +21,16 @@ IF(NOT WIN32)
|
||||
OPTION(WITH_OPENSSL "enables SSL support" ON)
|
||||
ELSE()
|
||||
OPTION(WITH_OPENSSL "enables SSL support" OFF)
|
||||
OPTION(WITH_RTC "enables run time checks for debug builds" OFF)
|
||||
ENDIF()
|
||||
|
||||
OPTION(WITH_SQLITE "Enables Sqlite support" OFF)
|
||||
OPTION(WITH_EXTERNAL_ZLIB "Enables use of external zlib" OFF)
|
||||
###############
|
||||
|
||||
IF(WITH_RTC)
|
||||
SET(RTC_OPTIONS "/RTC1 /RTCc")
|
||||
ENDIF()
|
||||
|
||||
IF(MSVC)
|
||||
# Speedup system tests
|
||||
@@ -39,7 +43,7 @@ IF(MSVC)
|
||||
IF (NOT COMPILER_FLAGS STREQUAL "")
|
||||
STRING(REPLACE "/MD" "/MT" COMPILER_FLAGS ${COMPILER_FLAGS})
|
||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET(COMPILER_FLAGS "${COMPILER_FLAGS} /RTC1 /RTCc")
|
||||
SET(COMPILER_FLAGS "${COMPILER_FLAGS} ${RTC_OPTIONS}")
|
||||
STRING(REPLACE "/Zi" "/ZI" COMPILER_FLAGS ${COMPILER_FLAGS})
|
||||
ENDIF()
|
||||
MESSAGE (STATUS "CMAKE_${COMPILER}_FLAGS_${BUILD_TYPE}= ${COMPILER_FLAGS}")
|
||||
|
@@ -127,7 +127,6 @@ ELSE()
|
||||
../zlib/compress.c
|
||||
../zlib/crc32.c
|
||||
../zlib/deflate.c
|
||||
../zlib/example.c
|
||||
../zlib/gzclose.c
|
||||
../zlib/gzlib.c
|
||||
../zlib/gzread.c
|
||||
|
@@ -31,8 +31,8 @@
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef MYSQL_SERVER
|
||||
#include <violite.h>
|
||||
#ifndef _WIN32
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PACKET_LENGTH (256L*256L*256L-1)
|
||||
@@ -114,8 +114,6 @@ int my_net_init(NET *net, Vio* vio)
|
||||
{
|
||||
if (!(net->buff=(uchar*) my_malloc(net_buffer_length,MYF(MY_WME | MY_ZEROFILL))))
|
||||
return 1;
|
||||
// if (net_buffer_length > max_allowed_packet)
|
||||
// max_allowed_packet=net_buffer_length;
|
||||
max_allowed_packet= net->max_packet_size= MAX(net_buffer_length, max_allowed_packet);
|
||||
net->buff_end=net->buff+(net->max_packet=net_buffer_length);
|
||||
net->vio = vio;
|
||||
@@ -166,13 +164,10 @@ static my_bool net_realloc(NET *net, size_t length)
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
|
||||
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length, MYF(MY_WME))))
|
||||
if (!(buff=(uchar*) my_realloc((char*) net->buff, pkt_length + 1, MYF(MY_WME))))
|
||||
{
|
||||
DBUG_PRINT("info", ("Out of memory"));
|
||||
net->error=1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_OUT_OF_RESOURCES;
|
||||
#endif
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
net->buff=net->write_pos=buff;
|
||||
@@ -180,21 +175,45 @@ static my_bool net_realloc(NET *net, size_t length)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SOCKET
|
||||
static ssize_t net_check_if_data_available(Vio *vio)
|
||||
|
||||
/* check if the socket is still alive */
|
||||
static my_bool net_check_socket_status(my_socket sock)
|
||||
{
|
||||
ssize_t length= 0;
|
||||
|
||||
if (vio->type != VIO_TYPE_SOCKET &&
|
||||
vio->type != VIO_TYPE_TCPIP)
|
||||
return 0;
|
||||
|
||||
if (vio_read_peek(vio, (size_t *)&length))
|
||||
return -1;
|
||||
|
||||
return length;
|
||||
}
|
||||
#ifndef _WIN32
|
||||
struct pollfd poll_fd;
|
||||
#else
|
||||
FD_SET sfds;
|
||||
struct timeval tv= {0,0};
|
||||
#endif
|
||||
int res;
|
||||
#ifndef _WIN32
|
||||
memset(&poll_fd, 0, sizeof(struct pollfd));
|
||||
poll_fd.events= POLLPRI | POLLIN;
|
||||
poll_fd.fd= sock;
|
||||
|
||||
res= poll(&poll_fd, 1, 0);
|
||||
if (res <= 0) /* timeout or error */
|
||||
return FALSE;
|
||||
if (!(poll_fd.revents & (POLLIN | POLLPRI)))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
#else
|
||||
/* We can't use the WSAPoll function, it's broken :-(
|
||||
(see Windows 8 Bugs 309411 - WSAPoll does not report failed connections)
|
||||
Instead we need to use select function:
|
||||
If TIMEVAL is initialized to {0, 0}, select will return immediately;
|
||||
this is used to poll the state of the selected sockets.
|
||||
*/
|
||||
FD_ZERO(&sfds);
|
||||
FD_SET(sock, &sfds);
|
||||
|
||||
res= select(sock + 1, &sfds, NULL, NULL, &tv);
|
||||
if (res > 0 && FD_ISSET(sock, &sfds))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* Remove unwanted characters from connection */
|
||||
|
||||
@@ -202,10 +221,19 @@ void net_clear(NET *net)
|
||||
{
|
||||
DBUG_ENTER("net_clear");
|
||||
|
||||
#ifdef DEBUG_SOCKET
|
||||
DBUG_ASSERT(net_check_if_data_available(net->vio) < 2);
|
||||
#endif
|
||||
|
||||
/* see conc-71: we need to check the socket status first:
|
||||
if the socket is dead we set net->error, so net_flush
|
||||
will report an error */
|
||||
while (net_check_socket_status(net->vio->sd))
|
||||
{
|
||||
/* vio_read returns size_t. so casting to long is required to check for -1 */
|
||||
if ((long)vio_read(net->vio, (gptr)net->buff, (size_t) net->max_packet) <= 0)
|
||||
{
|
||||
net->error= 2;
|
||||
DBUG_PRINT("info", ("socket disconnected"));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
}
|
||||
net->compress_pkt_nr= net->pkt_nr=0; /* Ready for new command */
|
||||
net->write_pos=net->buff;
|
||||
DBUG_VOID_RETURN;
|
||||
@@ -810,13 +838,14 @@ ulong my_net_read(NET *net)
|
||||
net->where_b=buffer_length;
|
||||
|
||||
if ((packet_length = my_real_read(net,(size_t *)&complen)) == packet_error)
|
||||
break;
|
||||
return packet_error;
|
||||
if (my_uncompress((unsigned char*) net->buff + net->where_b, &packet_length, &complen))
|
||||
{
|
||||
len= packet_error;
|
||||
net->error=2; /* caller will close socket */
|
||||
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
|
||||
break;
|
||||
return packet_error;
|
||||
}
|
||||
buffer_length+= complen;
|
||||
}
|
||||
@@ -827,11 +856,8 @@ ulong my_net_read(NET *net)
|
||||
len= current - start - 4;
|
||||
if (is_multi_packet)
|
||||
len-= 4;
|
||||
if (len != packet_error)
|
||||
{
|
||||
net->save_char= net->read_pos[len]; /* Must be saved */
|
||||
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
|
||||
}
|
||||
net->save_char= net->read_pos[len]; /* Must be saved */
|
||||
net->read_pos[len]=0; /* Safeguard for mysql_use_result */
|
||||
}
|
||||
#endif
|
||||
return (ulong)len;
|
||||
|
@@ -30,6 +30,38 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
#include "my_test.h"
|
||||
#include "ma_common.h"
|
||||
|
||||
static int test_conc71(MYSQL *my)
|
||||
{
|
||||
int rc;
|
||||
MYSQL_RES *res;
|
||||
MYSQL_ROW row;
|
||||
char *query;
|
||||
MYSQL *mysql;
|
||||
|
||||
/* uncomment if you want to test manually */
|
||||
return SKIP;
|
||||
|
||||
mysql= mysql_init(NULL);
|
||||
|
||||
|
||||
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, "utf8");
|
||||
mysql_options(mysql, MYSQL_OPT_COMPRESS, 0);
|
||||
mysql_options(mysql, MYSQL_INIT_COMMAND, "/*!40101 SET SQL_MODE='' */");
|
||||
mysql_options(mysql, MYSQL_INIT_COMMAND, "/*!40101 set @@session.wait_timeout=28800 */");
|
||||
|
||||
FAIL_IF(!mysql_real_connect(mysql, hostname, username, password, schema,
|
||||
port, socketname, 0), mysql_error(my));
|
||||
|
||||
diag("kill server");
|
||||
sleep(20);
|
||||
|
||||
rc= mysql_query(mysql, "SELECT 'foo' FROM DUAL");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
mysql_close(mysql);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static int test_conc70(MYSQL *my)
|
||||
{
|
||||
int rc;
|
||||
@@ -37,7 +69,7 @@ static int test_conc70(MYSQL *my)
|
||||
MYSQL_ROW row;
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
|
||||
mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
check_mysql_rc(rc, my);
|
||||
|
||||
mysql_query(my, "SET global max_allowed_packet=1024*1024*22");
|
||||
@@ -84,7 +116,7 @@ static int test_conc68(MYSQL *my)
|
||||
MYSQL_ROW row;
|
||||
MYSQL *mysql= mysql_init(NULL);
|
||||
|
||||
mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
rc= mysql_query(my, "SET @a:=@@max_allowed_packet");
|
||||
check_mysql_rc(rc, my);
|
||||
|
||||
mysql_query(my, "SET global max_allowed_packet=1024*1024*22");
|
||||
@@ -648,6 +680,7 @@ static int test_compressed(MYSQL *my)
|
||||
}
|
||||
|
||||
struct my_tests_st my_tests[] = {
|
||||
{"test_conc71", test_conc71, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_conc70", test_conc70, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_conc68", test_conc68, TEST_CONNECTION_DEFAULT, 0, NULL, NULL},
|
||||
{"test_compressed", test_compressed, TEST_CONNECTION_NONE, 0, NULL, NULL},
|
||||
|
@@ -65,6 +65,9 @@ static int test_logs(MYSQL *mysql)
|
||||
int rc;
|
||||
short id;
|
||||
|
||||
rc= mysql_query(mysql, "SET session sql_mode=''");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS test_logs");
|
||||
check_mysql_rc(rc, mysql);
|
||||
|
||||
|
3
unittest/libmariadb/my.cnf
Normal file
3
unittest/libmariadb/my.cnf
Normal file
@@ -0,0 +1,3 @@
|
||||
[conc-66]
|
||||
user=conc66
|
||||
password='test;#test'
|
@@ -1,13 +1,13 @@
|
||||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/zlib)
|
||||
|
||||
SET(SOURCE_FILES adler32.c compress.c crc32.c deflate.c example.c gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c minigzip.c trees.c uncompr.c zutil.c)
|
||||
SET(SOURCE_FILES adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c gzwrite.c infback.c inffast.c inflate.c inftrees.c minigzip.c trees.c uncompr.c zutil.c)
|
||||
|
||||
ADD_LIBRARY(zlib ${SOURCE_FILES})
|
||||
SET_TARGET_PROPERTIES(zlib PROPERTIES COMPILE_FLAGS
|
||||
"${CMAKE_SHARED_LIBRARY_C_FLAGS}")
|
||||
|
||||
INSTALL(TARGETS
|
||||
zlib
|
||||
RUNTIME DESTINATION "lib"
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib")
|
||||
INSTALL(TARGETS
|
||||
zlib
|
||||
RUNTIME DESTINATION "lib"
|
||||
LIBRARY DESTINATION "lib"
|
||||
ARCHIVE DESTINATION "lib")
|
||||
|
Reference in New Issue
Block a user