Bug #404 mysql_ping/mysql_real_connect in C API: invalid memory access ?
Submitted: 8 May 2003 13:59 Modified: 3 Jun 2003 5:45
Reporter: Mathias BAVAY Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version:3.23.52 OS:Linux (Linux)
Assigned to: Victor Vagin CPU Architecture:Any

[8 May 2003 13:59] Mathias BAVAY
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 !
[2 Jun 2003 4:55] Victor Vagin
Not enough information was provided for us to be able
to handle this bug. Please re-read the instructions at
http://bugs.mysql.com/how-to-report.php

If you can provide more information, feel free to add it
to this bug and change the status back to 'Open'.

Thank you for your interest in MySQL.

1. Unfortunately, I can not repeat this bug.
   Your program worked during 1 hour at my Suse Linux 7.2 without a hanging..
   valgrind-1.9.2 doesn't get any errors either..

2. Your program has some errors..
   Exactly, you call mysql_init every second without calling mysql_close!
   It's wrong! please, see 
   http://www.mysql.com/doc/en/mysql_init.html
   And you don't check that mysql_init is succesefull, it's wrong too.
   
   Further, You call mysql_select_db even if mysql_real_connect isn't 
   succesefull! It's forbiden at
   http://www.mysql.com/doc/en/mysql_real_connect.html

   So, I think the reason of hanging is memory overflow, 
   and then using of (MYSQL*)NULL..
[2 Jun 2003 10:46] Mathias BAVAY
This is my fault.... This (tricky) bug was on my side, not on MySQL side... I'm really sorry to have wasted your time for something which was not a 
bug in MySQL C API but my mistake in using that API.

Sincerly sorry,
Mathias Bavay
[3 Jun 2003 4:56] Victor Vagin
No feedback was provided. The bug is being suspended because
we assume that you are no longer experiencing the problem.
If this is not the case and you are able to provide the
information that was requested earlier, please do so and
change the status of the bug back to "Open". Thank you.
[3 Jun 2003 5:45] Lenz Grimmer
As it turned out not to be a bug, we close this report for now.