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

Reply via email to