Bug #62574 libmysqlclient statically compiled, mysql_close() hangs
Submitted: 29 Sep 2011 17:19 Modified: 5 Oct 2011 14:08
Reporter: Dario Fiumicello Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S2 (Serious)
Version:5.1.49 OS:Linux (Debian)
Assigned to: CPU Architecture:Any
Tags: static statically libmysqlclient c mysql_close hang

[29 Sep 2011 17:19] Dario Fiumicello
Description:
I have an application which uses mysql C api and I'd like to provide the option to compile libmysqlclient statically or shared.

When linking as shared everything is ok, but when I link it as static I get weird problems with mysql_close() function, which hangs every once is called.

This is how I link the application libraries when using shared libraries:

/usr/bin/gcc -O2 -Wall -g -lmysqlclient collector.o session_protocol.o data_protocol.o utils.o mysql_output.o signal.o queue.o md5.o -o collector

This is how I link the application libraries when using static libraries:

/usr/bin/gcc -O2 -Wall -g -lm -lz collector.o session_protocol.o data_protocol.o utils.o mysql_output.o signal.o queue.o md5.o /usr/lib/libmysqlclient.a -o collector

The line that hangs in static application is:
    mysql_close(&config->mysqlLink);

How to repeat:
Create an application which uses libmysqlclient libraries and execute a connectin cycle to database (i.e.: mysql_init(), mysql_query() mysql_close())

Compile the application with shared libraries and execute it. Then compile it with static libraries and execute it.
[30 Sep 2011 12:49] Valeriy Kravchuk
Please, check if the same problem still happens with a newer version, 5.1.59 (use official community binaries if possible). 

If it does, please, send code of smallest application that demonstrates the problem.
[30 Sep 2011 21:46] Dario Fiumicello
I tried the program below with both 5.1.49 and 5.1.59. It worked correctly with those two versions. compiled with:

gcc -lm -g mysql_test.c libmysqlclient.a -o mysql_test

Then I tried to debug my program using 5.1.59 and I got the same error. GDB reported this:

Program received signal SIGSEGV, Segmentation fault.
0x081e8830 in shutdown ()
(gdb) ^CQuit
(gdb) bt
#0  0x081e8830 in shutdown ()
#1  0x0807f328 in vio_close (vio=0x81ea2d0) at viosocket.c:275
#2  0x0807ebe1 in vio_delete (vio=0x81ea2d0) at vio.c:238
#3  0x0807a423 in end_server (mysql=0xbffff87c) at client.c:951
#4  0x0807a5ca in mysql_close (mysql=0xbffff87c) at client.c:2771
#5  0x0805404c in mysqlStart (config=0xbffff634) at mysql_output.c:82
#6  0x0804efa3 in collectorStart (argc=1, argv=0xbffffd24, config=0xbffff634, client=0x81e7c90) at collector.c:413
#7  0x0804e13c in main (argc=1, argv=0xbffffd24) at collector.c:147
(gdb) 

As you can see the segfault starts exactly when program enters in shutdown(). Also you can see that since libmysqlclient is compiled statically the adresses are 0x080xxxxx as far as they arrive to shutdown; then they became 0x081xxxxx and... SIGSEGV.

Line at viosocket.c:275 simply does:

    if (shutdown(vio->sd, SHUT_RDWR))

I set a breakpoint at it and when it is called vio->sd exists (it is set to 5) and is reported by lsof to be a valid descriptor:

collector 5049 root    5u  sock    0,6      0t0  18720 can't identify protocol

If I execute the program with libmysqlclient linked dinamically and set a breakpoint at the same place everything goes fine:

Breakpoint 1, vio_close (vio=0x80562d0) at viosocket.c:275
275	viosocket.c: No such file or directory.
	in viosocket.c
(gdb) bt
#0  vio_close (vio=0x80562d0) at viosocket.c:275
#1  0xb7e5d091 in vio_delete (vio=0x80562d0) at vio.c:238
#2  0xb7e588d3 in end_server (mysql=0xbffff87c) at client.c:951
#3  0xb7e58a7a in mysql_close (mysql=0xbffff87c) at client.c:2771
#4  0x0804f3dc in mysqlStart (config=0xbffff634) at mysql_output.c:82
#5  0x0804a333 in collectorStart (argc=1, argv=0xbffffd24, config=0xbffff634, client=0x8054910) at collector.c:413
#6  0x080494cc in main (argc=1, argv=0xbffffd24) at collector.c:147
(gdb) s
shutdown () at ../sysdeps/unix/sysv/linux/i386/socket.S:51
51	../sysdeps/unix/sysv/linux/i386/socket.S: No such file or directory.
	in ../sysdeps/unix/sysv/linux/i386/socket.S
Current language:  auto
The current source language is "auto; currently asm".
(gdb) 

As you can see it correctly steps into shutdown()

I suspect there is something wrong when jumping into shutdown() routine, maybe the address space is not correct when using statically linked libraries. It could be a libc bug or something else, I don't know. Anyway I didn't explain why it didn't happens whit the sample test program.

The sample program:

/* Simple C program that connects to MySQL Database server*/
#include <mysql.h>
#include <stdio.h>

main() {
   MYSQL *conn;
   MYSQL_RES *res;
   MYSQL_ROW row;

   char *server = "localhost";
   char *user = "root";
   char *password = "PASSWORD"; /* set me first */
   char *database = "mysql";

   conn = mysql_init(NULL);

   /* Connect to database */
   if (!mysql_real_connect(conn, server,
         user, password, database, 0, NULL, 0)) {
      fprintf(stderr, "%s\n", mysql_error(conn));
      exit(1);
   }

   /* send SQL query */
   if (mysql_query(conn, "show tables")) {
      fprintf(stderr, "%s\n", mysql_error(conn));
      exit(1);
   }

   res = mysql_use_result(conn);

   /* output table name */
   printf("MySQL Tables in mysql database:\n");
   while ((row = mysql_fetch_row(res)) != NULL)
      printf("%s \n", row[0]);

   /* close connection */
   mysql_free_result(res);
   mysql_close(conn);
}
[5 Oct 2011 14:08] Dario Fiumicello
We found the issue.

The segfaulting shutdown was at:

0x0807f513 <vio_close+51>:      call   0x81e9850 <shutdown>

Looking in our project we found that there is a struct called "shutdown". Now, guess where is the shutdown placed:

gdb) print &'collector.c'::shutdown
$6 = (struct {...} *) 0x81e9850

So the linker, when we use libmysqlclient statically, confuses the shutdown() call with the "shutdown" struct, thus jumping to that address produced a segfault.

I don't know if it is our fault or a linker fault (which does not even prompt a warning message for this ambiguity), anyway I'm going to talk about this with the gcc guys.

Sorry for the wrong report.