Description:
The connection is open and working between a client program and a remote mysql server.
When the server is down, mysql_ping is called every seconds in order to try to re-establish the connection (called lauched by an interruption).
After a random number of unsuccessfull tries (it could take 30 minutes), the client hangs up.
It seems to be a problem only while accessing a remote server. Valgrind 1.0.2 return some memory management errors in calls to libmysqlclient:
==22617== Invalid read of size 4
==22617== at 0x40269180: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x40264362: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin)
==22617== Address 0x42C394BC is 12 bytes inside a block of size 84 free'd
==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so)
==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026900D: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026449A: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617==
==22617== Invalid write of size 1
==22617== at 0x4003BF30: memcpy (vg_clientfuncs.c:509)
==22617== by 0x40264394: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin)
==22617== Address 0x42C39A80 is 0 bytes inside a block of size 8192 free'd
==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so)
==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x402687F5: (within /usr/lib/libmysqlclient.so.10.0.0)
==22617== by 0x402644B1: (within /usr/lib/libmysqlclient.so.10.0.0)
How to repeat:
here is my test program (adapt the sql server/table/fields in order to match your installation):
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include "/usr/include/mysql/mysql.h"
#define SQL_QUERY_LENGHT 256
/* global variables */
/*the declaration order is important, for data alignement issues */
FILE *std_msg;
FILE *std_err;
int flag_alrm;
/*************************************************/
/* global variables */
char sql_buf1[SQL_QUERY_LENGHT],sql_buf2[SQL_QUERY_LENGHT],sql_query[SQL_QUERY_LENGHT]; /* in case of an SQL logging, we will need some buffers */
MYSQL mysql;
/*************************************************/
/* functions */
int sql_init() {
/* initialization of the sql database connection */
/* return EXIT_SUCCESS or EXIT_FAILURE */
mysql_init(&mysql);
if (!mysql_real_connect(&mysql,"bicron","test","test","test",0,NULL,0)) {
fprintf(stderr, "sql_init: Failed to connect to database: Error: %s\n", mysql_error(&mysql));
}
if (mysql_select_db(&mysql,"test")) {
fprintf(stderr,"sql_init: Couldn't select database %s!\n%s\n","test", mysql_error(&mysql));
}
return EXIT_SUCCESS;
}
int sql_query_log() {
/* build and send an sql query to the sql server in order to log data fro ALL probes */
/* return EXIT_SUCCESS or EXIT_FAILURE */
/* we need to build a string like 'INSERT into table (field1,field2) values (value1,value2)' */
int number,probe_index;
sql_buf1[0]='\0';
sql_buf2[0]='\0';
number=snprintf(sql_query,(size_t)(SQL_QUERY_LENGHT*sizeof(char)),"INSERT into test (timestamps) values (now())");
if(number <= -1 || number >= (int)(SQL_QUERY_LENGHT*sizeof(char))) {
perror("sql_query: final query string building failure\n");
return EXIT_FAILURE;
}
fprintf(stdout,"Query=%s\n",sql_query);
fprintf(stderr,"mysql=%ld\n",mysql);
/* checking that the database is still there and if not, trying to reconnect */
if(mysql_ping(&mysql)){
//fprintf(std_err,"Trying to reconnect to the database...\n");
if(sql_init()== EXIT_FAILURE) {
return EXIT_FAILURE;
}
return EXIT_FAILURE;
}
if(mysql_query(&mysql,sql_query))
{
fprintf(stderr,"Query \"%s\" failed for %s@%s (%s)\n",sql_query,"test","localhost",mysql_error(&mysql));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
void sig_alrm(void) {
/* function called when a SIGALRM signal is catched */
flag_alrm=1;
}
int timer_init(long write_timer_duration) {
/* this is the initialization of signal catching and timer */
/* return EXIT_SUCCES or EXIT_FAILURE */
struct itimerval timer_parameters; /* parameters for the timer, in order to calculate cpm, dose... */
struct sigaction timer_act; /* for signal catching (for the timer) */
/* we want to catch the signal SIGALRM in order to use it as a timer */
timer_act.sa_handler=(void *)sig_alrm;
/* We don't want to block any other signals */
sigemptyset(&timer_act.sa_mask);
if (sigaction(SIGALRM,&timer_act,NULL) != EXIT_SUCCESS) {
perror("timer_init: signal catching failed for SIGALRM");
return EXIT_FAILURE;
}
/* setting up a timer, which is going to send SIGALRM every average_length seconds */
timer_parameters.it_value.tv_sec=0;
timer_parameters.it_value.tv_usec=write_timer_duration;
timer_parameters.it_interval.tv_sec=0;
timer_parameters.it_interval.tv_usec=write_timer_duration;
flag_alrm=0;
if((setitimer (ITIMER_REAL,&timer_parameters,NULL)) != EXIT_SUCCESS) {
perror("timer_init: timer setup failed");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
int sequencer_init(void) {
/* starting signal catching and timer */
/* return EXIT_SUCCESS or EXIT_FAILURE */
struct timeval timeout; /* time out structure for "select" */
if(timer_init(10000) == EXIT_FAILURE) {
perror("sequencer_init: Timer initialization failure");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
/* ******************************************************************************************* */
main(int argn,char *argv[]){
int flag_stop;
/* initializations */
std_msg=stdout;
std_err=stderr;
flag_stop=0;
/* MySQL initialization if necessary */
if(sql_init()== EXIT_FAILURE) return EXIT_FAILURE;
/* launching sequencer (timer+signal catching) */
if(sequencer_init()== EXIT_FAILURE) return EXIT_FAILURE;
do {
if(flag_alrm==1) {
sql_query_log();
flag_alrm=0;
}
} while (!flag_stop);
/* stopping MySQL if necessary */
//mysql_close(&settings.mysql);
/*****************************************************************************************************/
/* ending the program */
return EXIT_SUCCESS;
}
Suggested fix:
Check memory access in mysql_ping/mysql_real_connect/mysql_select_db !
Description: The connection is open and working between a client program and a remote mysql server. When the server is down, mysql_ping is called every seconds in order to try to re-establish the connection (called lauched by an interruption). After a random number of unsuccessfull tries (it could take 30 minutes), the client hangs up. It seems to be a problem only while accessing a remote server. Valgrind 1.0.2 return some memory management errors in calls to libmysqlclient: ==22617== Invalid read of size 4 ==22617== at 0x40269180: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x40264362: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin) ==22617== Address 0x42C394BC is 12 bytes inside a block of size 84 free'd ==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so) ==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x4026900D: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x4026449A: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== ==22617== Invalid write of size 1 ==22617== at 0x4003BF30: memcpy (vg_clientfuncs.c:509) ==22617== by 0x40264394: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x4026726F: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x804A311: sql_query_log (in /home/bicron/software/developpement/gm4lin_1.2.3/gm4lin) ==22617== Address 0x42C39A80 is 0 bytes inside a block of size 8192 free'd ==22617== at 0x4003B821: free (in /usr/lib/valgrind/valgrind.so) ==22617== by 0x4026A2D3: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x402687F5: (within /usr/lib/libmysqlclient.so.10.0.0) ==22617== by 0x402644B1: (within /usr/lib/libmysqlclient.so.10.0.0) How to repeat: here is my test program (adapt the sql server/table/fields in order to match your installation): #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <sys/time.h> #include "/usr/include/mysql/mysql.h" #define SQL_QUERY_LENGHT 256 /* global variables */ /*the declaration order is important, for data alignement issues */ FILE *std_msg; FILE *std_err; int flag_alrm; /*************************************************/ /* global variables */ char sql_buf1[SQL_QUERY_LENGHT],sql_buf2[SQL_QUERY_LENGHT],sql_query[SQL_QUERY_LENGHT]; /* in case of an SQL logging, we will need some buffers */ MYSQL mysql; /*************************************************/ /* functions */ int sql_init() { /* initialization of the sql database connection */ /* return EXIT_SUCCESS or EXIT_FAILURE */ mysql_init(&mysql); if (!mysql_real_connect(&mysql,"bicron","test","test","test",0,NULL,0)) { fprintf(stderr, "sql_init: Failed to connect to database: Error: %s\n", mysql_error(&mysql)); } if (mysql_select_db(&mysql,"test")) { fprintf(stderr,"sql_init: Couldn't select database %s!\n%s\n","test", mysql_error(&mysql)); } return EXIT_SUCCESS; } int sql_query_log() { /* build and send an sql query to the sql server in order to log data fro ALL probes */ /* return EXIT_SUCCESS or EXIT_FAILURE */ /* we need to build a string like 'INSERT into table (field1,field2) values (value1,value2)' */ int number,probe_index; sql_buf1[0]='\0'; sql_buf2[0]='\0'; number=snprintf(sql_query,(size_t)(SQL_QUERY_LENGHT*sizeof(char)),"INSERT into test (timestamps) values (now())"); if(number <= -1 || number >= (int)(SQL_QUERY_LENGHT*sizeof(char))) { perror("sql_query: final query string building failure\n"); return EXIT_FAILURE; } fprintf(stdout,"Query=%s\n",sql_query); fprintf(stderr,"mysql=%ld\n",mysql); /* checking that the database is still there and if not, trying to reconnect */ if(mysql_ping(&mysql)){ //fprintf(std_err,"Trying to reconnect to the database...\n"); if(sql_init()== EXIT_FAILURE) { return EXIT_FAILURE; } return EXIT_FAILURE; } if(mysql_query(&mysql,sql_query)) { fprintf(stderr,"Query \"%s\" failed for %s@%s (%s)\n",sql_query,"test","localhost",mysql_error(&mysql)); return EXIT_FAILURE; } return EXIT_SUCCESS; } void sig_alrm(void) { /* function called when a SIGALRM signal is catched */ flag_alrm=1; } int timer_init(long write_timer_duration) { /* this is the initialization of signal catching and timer */ /* return EXIT_SUCCES or EXIT_FAILURE */ struct itimerval timer_parameters; /* parameters for the timer, in order to calculate cpm, dose... */ struct sigaction timer_act; /* for signal catching (for the timer) */ /* we want to catch the signal SIGALRM in order to use it as a timer */ timer_act.sa_handler=(void *)sig_alrm; /* We don't want to block any other signals */ sigemptyset(&timer_act.sa_mask); if (sigaction(SIGALRM,&timer_act,NULL) != EXIT_SUCCESS) { perror("timer_init: signal catching failed for SIGALRM"); return EXIT_FAILURE; } /* setting up a timer, which is going to send SIGALRM every average_length seconds */ timer_parameters.it_value.tv_sec=0; timer_parameters.it_value.tv_usec=write_timer_duration; timer_parameters.it_interval.tv_sec=0; timer_parameters.it_interval.tv_usec=write_timer_duration; flag_alrm=0; if((setitimer (ITIMER_REAL,&timer_parameters,NULL)) != EXIT_SUCCESS) { perror("timer_init: timer setup failed"); return EXIT_FAILURE; } return EXIT_SUCCESS; } int sequencer_init(void) { /* starting signal catching and timer */ /* return EXIT_SUCCESS or EXIT_FAILURE */ struct timeval timeout; /* time out structure for "select" */ if(timer_init(10000) == EXIT_FAILURE) { perror("sequencer_init: Timer initialization failure"); return EXIT_FAILURE; } return EXIT_SUCCESS; } /* ******************************************************************************************* */ main(int argn,char *argv[]){ int flag_stop; /* initializations */ std_msg=stdout; std_err=stderr; flag_stop=0; /* MySQL initialization if necessary */ if(sql_init()== EXIT_FAILURE) return EXIT_FAILURE; /* launching sequencer (timer+signal catching) */ if(sequencer_init()== EXIT_FAILURE) return EXIT_FAILURE; do { if(flag_alrm==1) { sql_query_log(); flag_alrm=0; } } while (!flag_stop); /* stopping MySQL if necessary */ //mysql_close(&settings.mysql); /*****************************************************************************************************/ /* ending the program */ return EXIT_SUCCESS; } Suggested fix: Check memory access in mysql_ping/mysql_real_connect/mysql_select_db !