[CONC-316] SEGV from mariadb_reconnect - extension is corrupted on a reconnect Created: 2018-03-14  Updated: 2018-04-18  Resolved: 2018-04-18

Status: Closed
Project: MariaDB Connector/C
Component/s: None
Affects Version/s: 3.0.3
Fix Version/s: N/A

Type: Bug Priority: Major
Reporter: Nicolas Rochelemagne Assignee: Georg Richter
Resolution: Duplicate Votes: 0
Labels: None
Environment:

CentOS 7



 Description   

I ve compiled mariadb-connector-c 3.0.3 from sources with MySQLcompat enabled

-DWITH_MYSQLCOMPAT=1

then upgraded the perl module DBD::mysql to version 4.046_01

While running a test that does

 
dbh->do("select 12");
dbh->disconnect;
# undef doh + reconnect
dbh->do("select 12");

I can notice a SEGV coming from libmariadb/mariadb_lib.c:1647 which looks like this for me

   │1637    my_bool STDCALL mariadb_reconnect(MYSQL *mysql)                                                                                                                                │
   │1638    {                                                                                                                                                                              │
   │1639      MYSQL tmp_mysql;                                                                                                                                                             │
   │1640      struct my_hook_data hook_data;                                                                                                                                               │
   │1641      struct mysql_async_context *ctxt= NULL;                                                                                                                                      │
   │1642      LIST *li_stmt= mysql->stmts;                                                                                                                                                 │
   │1643                                                                                                                                                                                   │
   │1644      /* check if connection handler is active */                                                                                                                                  │
   │1645      if (IS_CONNHDLR_ACTIVE(mysql))                                                                                                                                               │
   │1646      {                                                                                                                                                                            │
  >│1647        if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reconnect)                                                                                 │
   │1648          return(mysql->extension->conn_hdlr->plugin->reconnect(mysql));                                                                                                           │
   │1649      }                                                                                                                                                                            │
   │1650                                                                                                                                                                                   │
   │1651      if (!mysql->options.reconnect ||                                                                                                                                             │
   │1652          (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info)                                                                                                    │
   │1653      {                                                                                                                                                                            │
   │1654       /* Allow reconnect next time */                                                                                                                                             │
   │1655        mysql->server_status&= ~SERVER_STATUS_IN_TRANS;                                                                                                                            │
   │1656        my_set_error(mysql, CR_SERVER_GONE_ERROR, SQLSTATE_UNKNOWN, 0);

the gdb backtrace is

Program received signal SIGSEGV, Segmentation fault.
0x00007fffeed239e7 in mariadb_reconnect (mysql=0x130af10) at /root/rpmbuild/BUILD/mariadb-connector-c-3.0.3-src/libmariadb/mariadb_lib.c:1647
1647	    if (mysql->extension->conn_hdlr->plugin && mysql->extension->conn_hdlr->plugin->reconnect)
(gdb) bt
#0  0x00007fffeed239e7 in mariadb_reconnect (mysql=0x130af10) at /root/rpmbuild/BUILD/mariadb-connector-c-3.0.3-src/libmariadb/mariadb_lib.c:1647
#1  0x00007fffeed23faa in mthd_my_send_cmd (mysql=0x130af10, command=COM_QUERY, arg=0x12faa40 "SELECT 12;", length=10, skipp_check=<optimized out>, opt_arg=0x0) at /root/rpmbuild/BUILD/mariadb-connector-c-3.0.3-src/libmariadb/mariadb_lib.c:376
#2  0x00007fffeed21ca1 in mysql_real_query (mysql=0x130af10, query=0x12faa40 "SELECT 12;", length=<optimized out>) at /root/rpmbuild/BUILD/mariadb-connector-c-3.0.3-src/libmariadb/mariadb_lib.c:2249
#3  0x00007fffeef73cee in mysql_st_internal_execute (h=h@entry=0x134eda0, statement=statement@entry=0x1640498, attribs=attribs@entry=0x0, num_params=num_params@entry=0, params=params@entry=0x0, result=result@entry=0x7fffffffdac8, svsock=0x130af10, use_mysql_use_result=use_mysql_use_result@entry=0) at dbdimp.c:3568
#4  0x00007fffeef7a49b in XS_DBD__mysql__db_do (cv=<optimized out>) at mysql.xs:450
#5  0x00007fffef194355 in XS_DBI_dispatch () from /usr/local/cpanel/3rdparty/perl/526/lib64/perl5/cpanel_lib/x86_64-linux-64int/auto/DBI/DBI.so
#6  0x00007ffff78ea39d in Perl_pp_entersub () from /usr/local/cpanel/3rdparty/perl/526/lib64/perl5/5.26.0/x86_64-linux-64int/CORE/libperl.so
#7  0x00007ffff78e34c6 in Perl_runops_standard () from /usr/local/cpanel/3rdparty/perl/526/lib64/perl5/5.26.0/x86_64-linux-64int/CORE/libperl.so
#8  0x00007ffff7887590 in perl_run () from /usr/local/cpanel/3rdparty/perl/526/lib64/perl5/5.26.0/x86_64-linux-64int/CORE/libperl.so
#9  0x0000000000400d73 in main ()

more debug informations from gdb

 
(gdb) p mysql->extension
$4 = (struct st_mariadb_extension *) 0x16546d0
(gdb) p *( mysql->extension )
$5 = {
  conn_hdlr = 0x1660230,
  session_state =     {[0] = {
      list = 0x0,
      current = 0x0
    },
    [1] = {
      list = 0x0,
      current = 0x0
    },
    [2] = {
      list = 0x0,
      current = 0x0
    },
    [3] = {
      list = 0x0,
      current = 0x0
    },
    [4] = {
      list = 0x0,
      current = 0x0
    },
    [5] = {
      list = 0xffffffff,
      current = 0x0
    }},
  mariadb_client_flag = 10169976539133969351,
  mariadb_server_capabilities = 0
}
(gdb) p mysql->extension->conn_hdlr
$6 = (MA_CONNECTION_HANDLER *) 0x1660230
(gdb) p * mysql->extension->conn_hdlr
$7 = {
  plugin = 0x1200003732,
  data = 0x81,
  active = 16 '\020',
  free_data = 88 'X'
}
(gdb) p mysql->extension->conn_hdlr->plugin
$8 = (struct st_ma_connection_plugin *) 0x1200003732
(gdb) p *( mysql->extension->conn_hdlr->plugin )
Cannot access memory at address 0x1200003732

As you can see the plugin address is incorrectly set or not initialized



 Comments   
Comment by Nicolas Rochelemagne [ 2018-03-14 ]

when adding a breakpoint to the function mariadb_reconnect

my_bool STDCALL mariadb_reconnect(MYSQL *mysql)

the first call as an extension clean

(gdb) p * (mysql->extension)
$5 = {
  conn_hdlr = 0x133b140,
  session_state =     {[0] = {
      list = 0x0,
      current = 0x0
    },
    [1] = {
      list = 0x0,
      current = 0x0
    },
    [2] = {
      list = 0x0,
      current = 0x0
    },
    [3] = {
      list = 0x0,
      current = 0x0
    },
    [4] = {
      list = 0x0,
      current = 0x0
    },
    [5] = {
      list = 0xffffffff,
      current = 0x0
    }},
  mariadb_client_flag = 13344912537984083775,
  mariadb_server_capabilities = 0
}

but the second call to mariadb_reconnect chas a corrupted extension...

 
(gdb) p * (mysql->extension)
$8 = {
  conn_hdlr = 0x202020202020200a,
  session_state =     {[0] = {
      list = 0x7465722420796d20,
      current = 0x43203d20206c6176
    },
    [1] = {
      list = 0x65706f3a3a45524f,
      current = 0x2c5d305b5f24286e
    },
    [2] = {
      list = 0x202c5d315b5f2420,
      current = 0x23242e2e325b5f40
    },
    [3] = {
      list = 0x2020200a3b295d5f,
      current = 0x20796d2020202020
    },
    [4] = {
      list = 0x747865746e6f6324,
      current = 0x6c61637322203d20
    },
    [5] = {
      list = 0x2020200a3b227261,
      current = 0x6d67617270200020
    }},
  mariadb_client_flag = 34745805432496225,
  mariadb_server_capabilities = 128
}

the mysql object itself seems valid

 
p *mysql
$9 = {
  net = {
    pvio = 0x0,
    buff = 0x0,
    buff_end = 0x1339b00 "autodie",
    write_pos = 0x1337b00 "s;\n        }\n    \n        my $retval  = CORE::open($_[0]);\n        my $context = \"scalar\";\n    \n\n        \n        die autodie->throw(\n", ' ' <repeats 12 times>, "function => q{CORE::open}, args => [ $_[0] ],\n        "...,
    read_pos = 0x1337b00 "s;\n        }\n    \n        my $retval  = CORE::open($_[0]);\n        my $context = \"scalar\";\n    \n\n        \n        die autodie->throw(\n", ' ' <repeats 12 times>, "function => q{CORE::open}, args => [ $_[0] ],\n        "...,
    fd = -1,
    remain_in_buf = 0,
    length = 0,
    buf_length = 0,
    where_b = 0,
    max_packet = 8192,
    max_packet_size = 1073741824,
    pkt_nr = 1,
    compress_pkt_nr = 0,
    write_timeout = 0,
    read_timeout = 30,
    retry_count = 0,
    fcntl = 0,
    return_status = 0x0,
    reading_or_writing = 0 '\000',
    save_char = 0 '\000',
    unused_1 = 0 '\000',
    unused_2 = 0 '\000',
    compress = 0 '\000',
    unused_3 = 0 '\000',
    unused_4 = 0x0,
    last_errno = 0,
    error = 0 '\000',
    unused_5 = 0 '\000',
    unused_6 = 0 '\000',
    last_error =       '\000' <repeats 511 times>,
    sqlstate =       "00000",
    extension = 0x133b760
  },
  unused_0 = 0x0,
  host = 0x0,
  user = 0x0,
  passwd = 0x0,
  unix_socket = 0x0,
  server_version = 0x0,
  host_info = 0x0,
  info = 0x0,
  db = 0x0,
  charset = 0x7fffeef5d428 <mariadb_compiled_charsets+360>,
  fields = 0x0,
  field_alloc = {
    free = 0x0,
    used = 0x0,
    pre_alloc = 0x0,
    min_malloc = 32,
    block_size = 8168,
    block_num = 4,
    first_block_usage = 0,
    error_handler = 0x0
  },
  affected_rows = 18446744073709551615,
  insert_id = 0,
  extra_info = 0,
  thread_id = 5250,
  packet_length = 0,
  port = 3306,
  client_flag = 10461711,
  server_capabilities = 2155870207,
  protocol_version = 10,
  field_count = 0,
  server_status = 2,
  server_language = 8,
  warning_count = 0,
  options = {
    connect_timeout = 0,
    read_timeout = 0,
    write_timeout = 0,
    port = 0,
    protocol = 0,
    client_flag = 0,
    host = 0x0,
    user = 0x0,
    password = 0x0,
    unix_socket = 0x0,
    db = 0x0,
    init_command = 0x0,
    my_cnf_file = 0x0,
    my_cnf_group = 0x0,
    charset_dir = 0x0,
    charset_name = 0x0,
    ssl_key = 0x0,
    ssl_cert = 0x0,
    ssl_ca = 0x0,
    ssl_capath = 0x0,
    ssl_cipher = 0x0,
    shared_memory_base_name = 0x0,
    max_allowed_packet = 0,
    use_ssl = 0 '\000',
    compress = 0 '\000',
    named_pipe = 0 '\000',
    reconnect = 0 '\000',
    unused_1 = 0 '\000',
    unused_2 = 0 '\000',
    unused_3 = 0 '\000',
    methods_to_use = MYSQL_OPT_CONNECT_TIMEOUT,
    bind_address = 0x0,
    secure_auth = 0 '\000',
    report_data_truncation = 0 '\000',
    local_infile_init = 0x0,
    local_infile_read = 0x0,
    local_infile_end = 0x0,
    local_infile_error = 0x0,
    local_infile_userdata = 0x0,
    extension = 0x0
  },
  status = MYSQL_STATUS_READY,
  free_me = 0 '\000',
  unused_1 = 0 '\000',
  scramble_buff =     "lv,s!F~it-|LFZqJ[m3R",
  unused_2 = 0 '\000',
  unused_3 = 0x0,
  unused_4 = 0x0,
  unused_5 = 0x0,
  unused_6 = 0x0,
  stmts = 0x0,
  methods = 0x7fffeef65920 <MARIADB_DEFAULT_METHODS>,
  thd = 0x0,
  unbuffered_fetch_owner = 0x0,
  info_buffer = 0x0,
  extension = 0x1333830
}

the extension address is the same between the two calls but something clear it or corrupt it

Comment by Nicolas Rochelemagne [ 2018-03-14 ]

wonder if it s not coming from DBI in dbdimp.c in mysql_db_reconnect when calling

 
   if (!dbd_db_disconnect(h, imp_dbh) || !my_login(aTHX_ h, imp_dbh))

mysql_db_reconnect abd maria_db_reconnect are similar
but the dbd_db_disconnect version from mariadb has some extra reinit...
view https://github.com/gooddata/DBD-MariaDB/blob/master/dbdimp.c#L2876

Comment by Nicolas Rochelemagne [ 2018-03-14 ]

I can confirm that patching DBD::mysql with the extra logic from mariadb_db_disconnect fixes the issue

fix submitted to DBD::mysql repo via https://github.com/perl5-dbi/DBD-mysql/pull/247

Comment by Georg Richter [ 2018-04-18 ]

Duplicate of CONC-289

Generated at Thu Feb 08 03:04:26 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.