Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-42077

mariabackup --backup aborts in get_log_file_path() on an empty --innodb-log-group-home-dir= (std::string::back() on an empty string)

    XMLWordPrintable

Details

    Description

      innodb_init_param() in extra/mariabackup/xtrabackup.cc (line 2580 on 10.11, 2602 on 12.3) replaces srv_log_group_home_dir with the default only when it is NULL, so an empty --innodb-log-group-home-dir= is kept. recv_sys_t::find_checkpoint() then calls get_log_file_path() (storage/innobase/log/log0log.cc), which does path.back() on the empty string and trips the libstdc++ assertion.

      No special server is needed; the test uses a fake server (perl) only because it needs no InnoDB. A non-empty value works (control). The behaviour on a release build was not checked.

      --source include/not_embedded.inc
      --source include/have_mariabackup.inc
       
      --echo #
      --echo # get_log_file_path() (storage/innobase/log/log0log.cc) calls path.back() on
      --echo # srv_log_group_home_dir. mariabackup keeps an empty --innodb-log-group-home-dir=
      --echo # (xtrabackup.cc replaces only a NULL value), so the string is empty.
      --echo #
       
      --exec $MYSQL -N -B -e "show variables" > $MYSQL_TMP_DIR/vuln_vars.txt
      --exec $MYSQL -N -B -e "show status like 'innodb_lsn_flushed'" > $MYSQL_TMP_DIR/vuln_status.txt
      --let $datadir= `SELECT @@datadir`
       
      perl;
      use IO::Socket::INET;
      sub pkt { my ($q, $b)= @_; substr(pack('V', length $b), 0, 3) . chr($q & 255) . $b }
      sub rd { my $s= shift; read($s, my $h, 4) or return; read($s, my $b, unpack('V', substr($h, 0, 3) . "\0")); (ord(substr $h, 3, 1) + 1, $b) }
      sub lstr { my $v= shift; my $n= length $v; ($n < 251 ? chr($n) : "\xfc" . pack('v', $n)) . $v }
      sub rs {
        my ($s, $q, $cols, @rows)= @_;
        my $o= pkt($q++, chr(scalar @$cols));
        $o.= pkt($q++, "\3def\0\0\0" . lstr($_) . lstr($_) . "\x0c" . pack('vVCvC', 33, 1024, 253, 0, 0) . "\0\0") for @$cols;
        $o.= pkt($q++, "\xfe" . pack('vv', 0, 2));
        $o.= pkt($q++, join '', map { defined $_ ? lstr($_) : "\xfb" } @$_) for @rows;
        print $s $o, pkt($q, "\xfe" . pack('vv', 0, 2));
      }
      sub slurp { open(my $h, '<', $_[0]) or die; my @r= map { chomp; [split /\t/, $_, 2] } <$h>; close $h; @r }
      my @real= slurp("$ENV{MYSQL_TMP_DIR}/vuln_vars.txt");
      my @stat= slurp("$ENV{MYSQL_TMP_DIR}/vuln_status.txt");
      my $l= IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1', LocalPort => 0) or die;
      open(my $f, '>', "$ENV{MYSQL_TMP_DIR}/vuln_port.txt") or die;
      print $f $l->sockport;
      close $f;
      fork and exit;
      open(STDIN, '<', '/dev/null'); open(STDOUT, '>', '/dev/null'); open(STDERR, '>&', \*STDOUT);
      alarm 120;
      while (my $s= $l->accept) {
        next if fork;
        alarm 120;
        close $l;
        my $ok= sub { print $s pkt($_[0], "\0\0\0" . pack('vv', 2, 0)) };
        print $s pkt(0, "\x0a10.11.6-MariaDB\0" . pack('V', 7) . "AAAAAAAA\0" . pack('v', 0xa20d) . "\x2d" . pack('v', 2) . pack('v', 8) . chr(21) . "\0" x 10 . "A" x 12 . "\0mysql_native_password\0");
        my ($q)= rd($s);
        print $s pkt($q, "\0\0\0" . pack('vv', 2, 0));
        while (my ($q, $b)= rd($s)) {
          my $sql= lc substr($b, 1);
          if ($sql =~ /^show variables like/) { rs($s, $q, [qw(k v)]) }
          elsif ($sql =~ /^show variables/) { rs($s, $q, [qw(k v)], @real) }
          elsif ($sql =~ /^show (global )?status like 'innodb_lsn_flushed'/) { rs($s, $q, [qw(k v)], @stat) }
          elsif ($sql =~ /^show grants/) { rs($s, $q, ['Grants'], ["GRANT ALL PRIVILEGES ON *.* TO 'root'\@'%' WITH GRANT OPTION"]) }
          elsif ($sql =~ /innodb_encrypt_log/) { rs($s, $q, ['x'], ['0']) }
          elsif ($sql =~ /innodb_encrypt_tables/) { rs($s, $q, ['x'], ['OFF']) }
          elsif ($sql =~ /^(select|show)/) { rs($s, $q, ['x']) }
          else { $ok->($q) } }
        exit }
      EOF
       
      --let $fake_port= `SELECT LOAD_FILE('$MYSQL_TMP_DIR/vuln_port.txt')`
       
      --echo # control: a non-empty --innodb-log-group-home-dir works
      --exec timeout 100 $XTRABACKUP --no-defaults --backup --target-dir=$MYSQL_TMP_DIR/vuln_backup --host=127.0.0.1 --port=$fake_port --user=root --password=x --skip-ssl --datadir=$datadir --innodb-log-group-home-dir=$datadir > $MYSQL_TMP_DIR/vuln_out.txt 2>&1
      --exec rm -rf $MYSQL_TMP_DIR/vuln_backup
       
      --echo # BUG if an empty --innodb-log-group-home-dir= aborts mariabackup
      --error 0,1
      --exec timeout 100 $XTRABACKUP --no-defaults --backup --target-dir=$MYSQL_TMP_DIR/vuln_backup --host=127.0.0.1 --port=$fake_port --user=root --password=x --skip-ssl --datadir=$datadir --innodb-log-group-home-dir= > $MYSQL_TMP_DIR/vuln_out.txt 2>&1
       
      --remove_file $MYSQL_TMP_DIR/vuln_port.txt
      --remove_file $MYSQL_TMP_DIR/vuln_out.txt
      --remove_file $MYSQL_TMP_DIR/vuln_vars.txt
      --remove_file $MYSQL_TMP_DIR/vuln_status.txt
      --exec rm -rf $MYSQL_TMP_DIR/vuln_backup

      The control passes; the second command fails with command ... failed with wrong error: 134:

      10.11.20-MariaDB-asan-debug-log source revision: 4ae8389be807b592fc909b99130350b4b8ced9b3
      /usr/include/c++/13/bits/basic_string.h:1341: std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::reference std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::back() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; reference = char&]: Assertion '!empty()' failed.
      Aborted
       
      #6  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::back /usr/include/c++/13/bits/basic_string.h:1341
      #7  get_log_file_path[abi:cxx11](char const*) /10.11/src/storage/innobase/log/log0log.cc:1552
      #8  recv_sys_t::find_checkpoint /10.11/src/storage/innobase/log/log0recv.cc:1749
      #9  xtrabackup_backup_func /10.11/src/extra/mariabackup/xtrabackup.cc:5664
      #10 main_low /10.11/src/extra/mariabackup/xtrabackup.cc:8020
      #11 main /10.11/src/extra/mariabackup/xtrabackup.cc:7795

      Same on 12.3.4 (f74586eebfe2a186087cfdda42be2d0ba398f01c).

      Attachments

        Activity

          People

            serg Sergei Golubchik
            alice Alice Sherepa
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.