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

Uninitialized tbl_len in dict_acquire_mdl_shared() in purge after DDL

    XMLWordPrintable

    Details

      Description

      A crash with the following (abbreviated) call stack was observed:

      #10 0x0000558a21f88cef in memcpy (__len=<optimized out>, __src=0x14af1c3f0740, __dest=0x14af1c3f0670)
          at /usr/include/x86_64-linux-gnu/bits/string_fortified.h:34
      #11 dict_acquire_mdl_shared<false> (table=table@entry=0x14aee838fef0, thd=thd@entry=0x558a24399468, 
          mdl=mdl@entry=0x558a24285b00, table_op=table_op@entry=DICT_TABLE_OP_NORMAL)
          at /test/10.5_opt/storage/innobase/dict/dict0dict.cc:904
      #12 0x0000558a21f84110 in dict_table_open_on_id (table_id=98, dict_locked=dict_locked@entry=false, 
          table_op=table_op@entry=DICT_TABLE_OP_NORMAL, thd=0x558a24399468, mdl=mdl@entry=0x558a24285b00)
          at /test/10.5_opt/storage/innobase/dict/dict0dict.cc:946
      #13 0x0000558a21e867e6 in row_purge_parse_undo_rec (thr=0x558a24285780, 
          updated_extern=0x14af1c3f0abe, undo_rec=0x558a24357470 "", node=0x558a24285960)
          at /test/10.5_opt/storage/innobase/row/row0purge.cc:933
      

      When I debugged a different occurrence of this, I noticed that tbl_len was uninitialized in the memcpy() call:

        size_t db1_len, tbl1_len;
       
        table->parse_name<!trylock>(db_buf1, tbl_buf1, &db1_len, &tbl1_len);
       
        if (*mdl)
        {
          if (db_len == db1_len && tbl_len == tbl1_len &&
              !memcmp(db_buf, db_buf1, db_len) &&
              !memcmp(tbl_buf, tbl_buf1, tbl_len))
            return table;
       
          /* The table was renamed. Release MDL for the old name and
          try to acquire MDL for the new name. */
          mdl_context->release_lock(*mdl);
          *mdl= nullptr;
        }
       
        db_len= db1_len;
        tbl_len= tbl1_len;
       
        memcpy(tbl_buf, tbl_buf1, tbl_len + 1);
        memcpy(db_buf, db_buf1, db_len + 1);
        goto retry;
      }
      

      When the function parse_name() returns false, it would leave tbl1_len uninitialized. The following patch should help:

      diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
      index e7cb05307d0..76537b2f41d 100644
      --- a/storage/innobase/dict/dict0dict.cc
      +++ b/storage/innobase/dict/dict0dict.cc
      @@ -758,7 +758,10 @@ bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
       
         if (tbl_len > TEMP_FILE_PREFIX_LENGTH
             && !strncmp(tbl_buf, TEMP_FILE_PREFIX, TEMP_FILE_PREFIX_LENGTH))
      +  {
      +    *tbl_name_len= tbl_len;
           return false;
      +  }
       
         if (char* is_part= strchr(tbl_buf, '#'))
           *is_part= '\0';
      

      It looks like db_len would always be initialized.

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              marko Marko Mäkelä
              Reporter:
              marko Marko Mäkelä
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved: