Hi there
I'm having trouble in a multi-threaded client with segfaults in
mysql_free_result(). After trawling the archives, I've found other people
reporting the same problem, but the fix in each case has been to make sure
that the pointer returned from mysql_store_result() is non-null. This is not
useful in my case, unfortunately, because I've done that. I humbly request
the assistance of the gathered ladies and gentlemen.
- Running on FreeBSD 4.3-STABLE.
- The library was compiled --without-server --enable-thread-safe-client, and
because my own code is compiled with -pthread, I've changed libtool to cause
libmysqlclient_r to be linked to libc_r. (Removes the ugly compile-time
warnings.)
- The client has a separate connection for each thread.
If anybody is able to suggest where I'm going wrong, I'd be most grateful.
allen
########################
A sample backtrace from gdb:
Program received signal SIGSEGV, Segmentation fault.
0x481496fd in _thread_leave_cancellation_point () from /usr/lib/libc_r.so.4
(gdb) backtrace
#0 0x481496fd in _thread_leave_cancellation_point () from
/usr/lib/libc_r.so.4
#1 0x48149b41 in free () from /usr/lib/libc_r.so.4
#2 0x480a0d23 in my_no_flags_free ()
from /usr/home/allen/mysql//lib/mysql/libmysqlclient_r.so.10
#3 0x480a38bc in free_root ()
from /usr/home/allen/mysql//lib/mysql/libmysqlclient_r.so.10
#4 0x4809ad5d in free_rows (cur=0x8090380) at libmysql.c:414
#5 0x4809b4bf in mysql_free_result (result=0x811f580) at libmysql.c:661
#6 0x80599ab in adm_cleanup (result=0x811f580) at admlayer.c:3115
#7 0x8050607 in do_setstatus (m=0xbfadcf84, mcon=0xbfadcd54, r=0xbfadcf60)
at messagehandling.c:2257
#8 0x8049990 in comms_handler (thing=0x8082000) at comms.c:230
#9 0x480d7ab3 in _thread_start () from /usr/lib/libc_r.so.4
#10 0x0 in ?? ()
########################
The equivalent situation recorded in the mysql log (options:
d:t:O,./trace/mysql.trace ) (excerpt)
>mysql_real_query
| enter: handle: bfadcd54
| query: Query = "UPDATE users SET status = '11' WHERE userid = '1'"
| >net_flush
| | >net_real_write
| | <net_real_write
| <net_flush
<mysql_real_query
>mysql_read_query_result
| >free_old_query
| <free_old_query
<mysql_read_query_result
>mysql_real_query
| enter: handle: bfadcd54
| query: Query = "UPDATE contact SET changed = 1 WHERE child_id = '1'"
| >net_flush
| | >net_real_write
| | <net_real_write
| <net_flush
<mysql_real_query
>mysql_read_query_result
| >free_old_query
| <free_old_query
<mysql_read_query_result
>mysql_real_query
| enter: handle: bfadcd54
| query: Query = "SELECT parent_id FROM contact WHERE child_id = '1'"
| >net_flush
| | >net_real_write
| | <net_real_write
| <net_flush
<mysql_real_query
>mysql_read_query_result
| >free_old_query
| <free_old_query
| >read_rows
| | exit: Got 1 rows
| <read_rows
| >unpack_fields
| <unpack_fields
<mysql_read_query_result
>mysql_store_result
| >read_rows
| | exit: Got 2 rows
| <read_rows
<mysql_store_result
>mysql_fetch_row
<mysql_fetch_row
>mysql_fetch_row
<mysql_fetch_row
>mysql_fetch_row
| info: end of data
<mysql_fetch_row
>mysql_free_result
| enter: mysql_res: 811f580
# file stops here
########################
The code that created the above traces (left out adm_retrievecontact()
because all it does
is call mysql_fetch_row() until running out of rows; has no bearing on the
situation as far as
I can see):
int do_setstatus( struct message *m, MYSQL *mcon, struct response *r )
{
unsigned int id;
char query[QUERYLENGTH];
struct setstatus *a = (struct setstatus *)m->attr;
void *result;
r->key = get_user_key( m->userid );
r->userid = m->userid;
if (! user_logged_in( m->userid )) {
return make_naksetstatus( IM_ERR_LGGDOUT, r->buffer );
}
if (a->newstatus == 0) {
return make_naksetstatus( IM_ERR_MSGATTR, r->buffer );
}
result = adm_setstatus( mcon, m->userid, a->newstatus, 1 );
if (! result) {
return make_naksetstatus( IM_ERR_SRVRERR, r->buffer );
}
while (adm_retrievecontact( result, &id ) == ADM_MORE_ROWS) {
record_contact( id );
}
adm_cleanup( result );
return make_acksetstatus( r->buffer );
}
###
int adm_cleanup( void *result )
{
mysql_free_result( (MYSQL_RES *)result );
return 0;
}
###
void *adm_setstatus( MYSQL *mcon, unsigned int userid, short newstatus,
short count )
{
int i;
char query[QUERYLENGTH];
MYSQL_RES *res;
if (count > ADM_MAXRECURS) {
return NULL;
}
sprintf( query,
"UPDATE users SET status = '%d' WHERE userid = '%u'",
newstatus,
userid );
mysql_query( mcon, query );
i = mysql_errno( mcon );
switch (i) {
case CR_SERVER_GONE_ERROR:
/* reconnect (recurse) */
case CR_SERVER_LOST:
/* recurse, try again */
return adm_setstatus( mcon, userid, newstatus, count
+ 1 );
break;
case 0:
/* success */
break;
default:
/* fail */
{
char logentry[LOGENTLEN];
sprintf( logentry,
"MySQL error %d: %s",
i,
mysql_error( mcon ) );
write_to_log( logentry );
}
return NULL;
break;
}
sprintf( query,
"UPDATE contact SET changed = 1 WHERE child_id = '%u'",
userid );
mysql_query( mcon, query );
i = mysql_errno( mcon );
switch (i) {
case CR_SERVER_GONE_ERROR:
/* reconnect (recurse) */
case CR_SERVER_LOST:
/* recurse, try again */
return adm_setstatus( mcon, userid, newstatus, count
+ 1 );
break;
case 0:
/* success */
break;
default:
/* fail */
{
char logentry[LOGENTLEN];
sprintf( logentry,
"MySQL error %d: %s",
i,
mysql_error( mcon ) );
write_to_log( logentry );
}
return NULL;
break;
}
sprintf( query,
"SELECT parent_id FROM contact WHERE child_id = '%u'",
userid );
mysql_query( mcon, query );
i = mysql_errno( mcon );
switch (i) {
case CR_SERVER_GONE_ERROR:
/* reconnect (recurse) */
case CR_SERVER_LOST:
/* recurse, try again */
return adm_setstatus( mcon, userid, newstatus, count
+ 1 );
break;
case 0:
/* success */
break;
default:
/* fail */
{
char logentry[LOGENTLEN];
sprintf( logentry,
"MySQL error %d: %s",
i,
mysql_error( mcon ) );
write_to_log( logentry );
}
return NULL;
break;
}
res = mysql_store_result( mcon );
return (void *)res;
}
--
Allen Grace
Dark Blue Sea Pty Ltd
ph +61 7 3007 0000
fax +61 7 3007 0001
***The opinions expressed in this email are my own and are not
representative of DBS Pty Ltd.***
---------------------------------------------------------------------
Before posting, please check:
http://www.mysql.com/manual.php (the manual)
http://lists.mysql.com/ (the list archive)
To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <mysql-unsubscribe-##L=##[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php