[devel] debug MySQL SEGV

Alexey Tourbin =?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Сб Авг 26 22:48:48 MSD 2006


On Sat, Aug 26, 2006 at 06:43:06PM +0400, Alexey Tourbin wrote:
> On Sat, Aug 26, 2006 at 06:17:31PM +0400, Alexey Tourbin wrote:
> > > интересно, а что скажет abi-drift?
> > Он вроде заглох послденее время.  message size >1M.
> 
> Впрочем, abi_drift проверят только разрешимость символов.  То есть с
> abi_drift можно спрашивать, когда приложение падает по undefined symbol.
> Здесь что-то более тонкое.  Я попробовал в gdb расковырять но там
> сплошные callback'и, в общем боюсь что мне слабо такое расковырять.
> Но попробую ещё...

gdb не помогает. :(  Поэтому я выбрал другую тактику, и у меня появилось
обоснованное подозрение.  Изложу подробно, как я реализую эту тактику;
это может быть назидательным для других maintainer'ов.

Тактика состоит в том, чтобы проверить, *что именно* мы компилируем.
Сначала стивится libMySQL-devel 5.0.22 и делается gcc -E всех
компилируемых файлов (препроцессор).  Потом ставится libMySQL-devel
5.0.24 и опять делается gcc -E всех комплируемых файлов.  Потом на
раскрытые таким образом исходники сравниваются.

$ cd ~build/DBD-mysql-3.0006
$ rm -fv *.o
removed `dbdimp.o'
removed `mysql.o'
$ sudo rpm -Uv ~sisyphus/files/i586/RPMS/libMySQL*-5.0.22-alt1.i586.rpm --force --nodeps
Preparing packages for installation...             
libMySQL-5.0.22-alt1
libMySQL-devel-5.0.22-alt1
$

Поставил старые пакеты libMySQL.  Теперь нужно зопатчить Makefile,
чтобы вместо gcc -c выполнялся gcc -E.

$ diff Makefile{-,}
--- Makefile-   2006-08-26 14:21:28 +0000
+++ Makefile    2006-08-26 18:26:45 +0000
@@ -309,7 +309,7 @@ BSLOADLIBS = 
 
 
 # --- MakeMaker const_cccmd section:
-CCCMD = $(CC) -c $(PASTHRU_INC) $(INC) \
+CCCMD = $(CC) -E $(PASTHRU_INC) $(INC) \
        $(CCFLAGS) $(OPTIMIZE) \
        $(PERLTYPE) $(MPOLLUTE) $(DEFINE_VERSION) \
        $(XS_DEFINE_VERSION)
$

Теперь при попытке комплияции .c.o в stdout будут сыпаться раскрытые
исходники.

$ make dbdimp.o |tail -5
SV *mysql_db_last_insert_id(SV *dbh, imp_dbh_t *imp_dbh,
        SV *catalog, SV *schema, SV *table, SV *field, SV *attr)
{
  return Perl_sv_2mortal(((PerlInterpreter *)pthread_getspecific((*Perl_Gthr_key_ptr(((void *)0))))), my_ulonglong2str(mysql_insert_id(&((imp_dbh_t*)imp_dbh)->mysql)));
}
$

Значит, вывод можно сохранять.

$ make dbdimp.o >dbdimp.E1
$ make mysql.o >mysql.E1
$ ls -l *.E1
-rw-r--r-- 1 at at 596132 Aug 26 22:30 dbdimp.E1
-rw-r--r-- 1 at at 608773 Aug 26 22:30 mysql.E1
$

Теперь осталось поставить новую библиотеку и опять сохранить вывод.

$ sudo rpm -Uv ~sisyphus/files/i586/RPMS/libMySQL*-5.0.24-alt1.i586.rpm                 
Preparing packages for installation...                                                                          
libMySQL-5.0.24-alt1
libMySQL-devel-5.0.24-alt1
$ make dbdimp.o >dbdimp.E2
$ make mysql.o >mysql.E2

А теперь -- то, ради чего всё делалось: сравниваем полностью раскрытые
исходники.

$ diff -upbB dbdimp.E[12]
--- dbdimp.E1   2006-08-26 18:30:07 +0000
+++ dbdimp.E2   2006-08-26 18:40:43 +0000
@@ -15290,7 +15290,8 @@ enum mysql_option
   MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
   MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
   MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
-  MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT
+  MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
+  MYSQL_OPT_SSL_VERIFY_SERVER_CERT
 };

 struct st_mysql_options {
@@ -15305,6 +15306,7 @@ struct st_mysql_options {
   char *ssl_ca;
   char *ssl_capath;
   char *ssl_cipher;
+  my_bool ssl_verify_server_cert;
   char *shared_memory_base_name;
   unsigned long max_allowed_packet;
   my_bool use_ssl;
@@ -15450,7 +15452,7 @@ typedef struct st_mysql_res {
   my_bool unbuffered_fetch_cancelled;
   const struct st_mysql_methods *methods;
 } MYSQL_RES;
-# 327 "/usr/include/mysql/mysql.h"
+# 329 "/usr/include/mysql/mysql.h"
 typedef struct st_mysql_manager
 {
   NET net;
@@ -15470,10 +15472,10 @@ typedef struct st_mysql_parameters
   unsigned long *p_max_allowed_packet;
   unsigned long *p_net_buffer_length;
 } MYSQL_PARAMETERS;
-# 357 "/usr/include/mysql/mysql.h"
+# 359 "/usr/include/mysql/mysql.h"
 int mysql_server_init(int argc, char **argv, char **groups);
 void mysql_server_end(void);
-# 371 "/usr/include/mysql/mysql.h"
+# 373 "/usr/include/mysql/mysql.h"
 MYSQL_PARAMETERS * mysql_get_parameters(void);


@@ -15515,6 +15517,7 @@ MYSQL * mysql_init(MYSQL *mysql);
 my_bool mysql_ssl_set(MYSQL *mysql, const char *key,
           const char *cert, const char *ca,
           const char *capath, const char *cipher);
+const char * mysql_get_ssl_cipher(MYSQL *mysql);
 my_bool mysql_change_user(MYSQL *mysql, const char *user,
        const char *passwd, const char *db);
 MYSQL * mysql_real_connect(MYSQL *mysql, const char *host,
@@ -15664,13 +15667,13 @@ int mysql_manager_fetch_line(MYSQL_MANAG
         char* res_buf,
        int res_buf_size);
 my_bool mysql_read_query_result(MYSQL *mysql);
-# 569 "/usr/include/mysql/mysql.h"
+# 572 "/usr/include/mysql/mysql.h"
 enum enum_mysql_stmt_state
 {
   MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE,
   MYSQL_STMT_FETCH_DONE
 };
-# 639 "/usr/include/mysql/mysql.h"
+# 642 "/usr/include/mysql/mysql.h"
 typedef struct st_mysql_bind
 {
   unsigned long *length;
@@ -15844,7 +15847,7 @@ my_bool mysql_autocommit(MYSQL * mysql,
 my_bool mysql_more_results(MYSQL *mysql);
 int mysql_next_result(MYSQL *mysql);
 void mysql_close(MYSQL *sock);
-# 837 "/usr/include/mysql/mysql.h"
+# 840 "/usr/include/mysql/mysql.h"
 unsigned long net_safe_read(MYSQL* mysql);
 # 22 "dbdimp.h" 2
 # 1 "/usr/include/mysql/mysqld_error.h" 1
/var/mail/at has mail!
$

И второй файл:

$ diff -upbB mysql.E[12]
--- mysql.E1    2006-08-26 18:30:19 +0000
+++ mysql.E2    2006-08-26 18:40:47 +0000
@@ -15291,7 +15291,8 @@ enum mysql_option
   MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT,
   MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
   MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
-  MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT
+  MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
+  MYSQL_OPT_SSL_VERIFY_SERVER_CERT
 };

 struct st_mysql_options {
@@ -15306,6 +15307,7 @@ struct st_mysql_options {
   char *ssl_ca;
   char *ssl_capath;
   char *ssl_cipher;
+  my_bool ssl_verify_server_cert;
   char *shared_memory_base_name;
   unsigned long max_allowed_packet;
   my_bool use_ssl;
@@ -15451,7 +15453,7 @@ typedef struct st_mysql_res {
   my_bool unbuffered_fetch_cancelled;
   const struct st_mysql_methods *methods;
 } MYSQL_RES;
-# 327 "/usr/include/mysql/mysql.h"
+# 329 "/usr/include/mysql/mysql.h"
 typedef struct st_mysql_manager
 {
   NET net;
@@ -15471,10 +15473,10 @@ typedef struct st_mysql_parameters
   unsigned long *p_max_allowed_packet;
   unsigned long *p_net_buffer_length;
 } MYSQL_PARAMETERS;
-# 357 "/usr/include/mysql/mysql.h"
+# 359 "/usr/include/mysql/mysql.h"
 int mysql_server_init(int argc, char **argv, char **groups);
 void mysql_server_end(void);
-# 371 "/usr/include/mysql/mysql.h"
+# 373 "/usr/include/mysql/mysql.h"
 MYSQL_PARAMETERS * mysql_get_parameters(void);


@@ -15516,6 +15518,7 @@ MYSQL * mysql_init(MYSQL *mysql);
 my_bool mysql_ssl_set(MYSQL *mysql, const char *key,
           const char *cert, const char *ca,
           const char *capath, const char *cipher);
+const char * mysql_get_ssl_cipher(MYSQL *mysql);
 my_bool mysql_change_user(MYSQL *mysql, const char *user,
        const char *passwd, const char *db);
 MYSQL * mysql_real_connect(MYSQL *mysql, const char *host,
@@ -15665,13 +15668,13 @@ int mysql_manager_fetch_line(MYSQL_MANAG
         char* res_buf,
        int res_buf_size);
 my_bool mysql_read_query_result(MYSQL *mysql);
-# 569 "/usr/include/mysql/mysql.h"
+# 572 "/usr/include/mysql/mysql.h"
 enum enum_mysql_stmt_state
 {
   MYSQL_STMT_INIT_DONE= 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE,
   MYSQL_STMT_FETCH_DONE
 };
-# 639 "/usr/include/mysql/mysql.h"
+# 642 "/usr/include/mysql/mysql.h"
 typedef struct st_mysql_bind
 {
   unsigned long *length;
@@ -15845,7 +15848,7 @@ my_bool mysql_autocommit(MYSQL * mysql,
 my_bool mysql_more_results(MYSQL *mysql);
 int mysql_next_result(MYSQL *mysql);
 void mysql_close(MYSQL *sock);
-# 837 "/usr/include/mysql/mysql.h"
+# 840 "/usr/include/mysql/mysql.h"
 unsigned long net_safe_read(MYSQL* mysql);
 # 22 "dbdimp.h" 2
 # 1 "/usr/include/mysql/mysqld_error.h" 1
$

Глядя на diff, *единственное*, что приходит в голову -- это изменение
в структуре st_mysql_options.  Прямо посреди структуры добавилось новое
поле.  Если эта структура каким-либо косвенным образом экспозируется
в качестве API, тогда это объясняет сбои в работе.  Это и есть то
обоснованное подозрение, о котором я написал в начале.

Теперь классический вопрос: что делать?
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип     : application/pgp-signature
Размер  : 189 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20060826/a72e045b/attachment-0001.bin>


Подробная информация о списке рассылки Devel