[MDEV-24245] REPAIR on ARCHIVE Database destroys TEXT Data Created: 2020-11-18  Updated: 2023-04-27

Status: Confirmed
Project: MariaDB Server
Component/s: Storage Engine - Archive
Affects Version/s: 10.3.25, 10.3, 10.4, 10.5
Fix Version/s: 10.4, 10.5

Type: Bug Priority: Major
Reporter: Johannes Grieb Assignee: Oleksandr Byelkin
Resolution: Unresolved Votes: 1
Labels: None
Environment:

Debian 10
mariadb-server-10.3/stable,now 1:10.3.25-0+deb10u1 amd64


Attachments: PNG File image-2020-11-18-21-43-03-414.png    

 Description   

After Repairing a Tabel due to power loss I detected all Text fields seem to be corrupted.

For reproduction I minified everything:

CREATE TABLE `TEST` ( 
	`text` TEXT NULL DEFAULT NULL
)
COLLATE='utf8_general_ci'
ENGINE=ARCHIVE
;
 
INSERT INTO `TEST` (`text`) VALUES ('Testtext');
 
REPAIR TABLE `TEST`;

Reading the Row before the REPAIR is fine.
When I try to read the Inserted row after the repair there is corrupted data.
This is also the case with OPTIMIZE

I can reproduce this on all my Debian 10 Machines.

Is it possible to reproduce this error for someone else.

Best regards



 Comments   
Comment by Alice Sherepa [ 2020-11-19 ]

Thank you for the report! The bug reproducible on MariaDB 10.3-10.5

install soname 'ha_archive';
 
create table t1 (`text` text) engine=archive;
insert into t1 (`text`) values ('testtext');
 
repair table t1;

on debug version:

10.3 eae9311fa2b15eb8a069844

Version: '10.3.28-MariaDB-debug-log' 
=================================================================
==2173==ERROR: AddressSanitizer: memcpy-param-overlap: memory ranges [0x60e000078d97,0x60e000078d9f) and [0x60e000078d93, 0x60e000078d9b) overlap
    #0 0x7fd86bc00105  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x3f105)
    #1 0x5600e39544c3 in Field_blob::pack(unsigned char*, unsigned char const*, unsigned int) /10.3/sql/field.cc:8787
    #2 0x5600e39a0ba4 in Field::pack(unsigned char*, unsigned char const*) /10.3/sql/field.h:1366
    #3 0x7fd86109a4f0 in ha_archive::pack_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:940
    #4 0x7fd8610998ef in ha_archive::real_write_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:878
    #5 0x7fd8610a024f in ha_archive::optimize(THD*, st_ha_check_opt*) /10.3/storage/archive/ha_archive.cc:1554
    #6 0x7fd86109f85a in ha_archive::repair(THD*, st_ha_check_opt*) /10.3/storage/archive/ha_archive.cc:1472
    #7 0x5600e39c6ff9 in handler::ha_repair(THD*, st_ha_check_opt*) /10.3/sql/handler.cc:4375
    #8 0x5600e360d073 in mysql_admin_table /10.3/sql/sql_admin.cc:808
    #9 0x5600e3613422 in Sql_cmd_repair_table::execute(THD*) /10.3/sql/sql_admin.cc:1425
    #10 0x5600e3213500 in mysql_execute_command(THD*) /10.3/sql/sql_parse.cc:6054
    #11 0x5600e321fd82 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /10.3/sql/sql_parse.cc:7839
    #12 0x5600e31f6421 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /10.3/sql/sql_parse.cc:1852
    #13 0x5600e31f2b5c in do_command(THD*) /10.3/sql/sql_parse.cc:1398
    #14 0x5600e35e2cbe in do_handle_one_connection(CONNECT*) /10.3/sql/sql_connect.cc:1403
    #15 0x5600e35e2576 in handle_one_connection /10.3/sql/sql_connect.cc:1308
    #16 0x5600e4d4512e in pfs_spawn_thread /10.3/storage/perfschema/pfs.cc:1869
    #17 0x7fd86bba7fa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
    #18 0x7fd86b52b4ce in clone (/lib/x86_64-linux-gnu/libc.so.6+0xf94ce)
 
0x60e000078d97 is located 119 bytes inside of 148-byte region [0x60e000078d20,0x60e000078db4)
allocated by thread T5 here:
    #0 0x7fd86bcaa330 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
    #1 0x5600e4f59880 in sf_malloc /10.3/mysys/safemalloc.c:118
    #2 0x5600e4f59de5 in sf_realloc /10.3/mysys/safemalloc.c:182
    #3 0x5600e4f293cf in my_realloc /10.3/mysys/my_malloc.c:166
    #4 0x7fd86109cb43 in ha_archive::fix_rec_buff(unsigned int) /10.3/storage/archive/ha_archive.cc:1218
    #5 0x7fd86109a142 in ha_archive::pack_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:926
    #6 0x7fd8610998ef in ha_archive::real_write_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:878
    #7 0x7fd86109b002 in ha_archive::write_row(unsigned char*) /10.3/storage/archive/ha_archive.cc:1056
    #8 0x5600e39d8201 in handler::ha_write_row(unsigned char*) /10.3/sql/handler.cc:6467
    #9 0x5600e3163dae in write_record(THD*, TABLE*, st_copy_info*) /10.3/sql/sql_insert.cc:2036
    #10 0x5600e315b49e in mysql_insert(THD*, TABLE_LIST*, List<Item>&, List<List<Item> >&, List<Item>&, List<Item>&, enum_duplicates, bool) /10.3/sql/sql_insert.cc:1072
    #11 0x5600e3207387 in mysql_execute_command(THD*) /10.3/sql/sql_parse.cc:4481
    #12 0x5600e321fd82 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /10.3/sql/sql_parse.cc:7839
    #13 0x5600e31f6421 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /10.3/sql/sql_parse.cc:1852
    #14 0x5600e31f2b5c in do_command(THD*) /10.3/sql/sql_parse.cc:1398
    #15 0x5600e35e2cbe in do_handle_one_connection(CONNECT*) /10.3/sql/sql_connect.cc:1403
    #16 0x5600e35e2576 in handle_one_connection /10.3/sql/sql_connect.cc:1308
    #17 0x5600e4d4512e in pfs_spawn_thread /10.3/storage/perfschema/pfs.cc:1869
    #18 0x7fd86bba7fa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
 
Thread T5 created by T0 here:
    #0 0x7fd86bc11db0 in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x50db0)
    #1 0x5600e4d4556a in spawn_thread_v1 /10.3/storage/perfschema/pfs.cc:1919
    #2 0x5600e2f066f4 in inline_mysql_thread_create /10.3/include/mysql/psi/mysql_thread.h:1275
    #3 0x5600e2f1fba8 in create_thread_to_handle_connection(CONNECT*) /10.3/sql/mysqld.cc:6658
    #4 0x5600e2f202fd in create_new_thread /10.3/sql/mysqld.cc:6728
    #5 0x5600e2f2147e in handle_connections_sockets() /10.3/sql/mysqld.cc:6986
    #6 0x5600e2f1ef1c in mysqld_main(int, char**) /10.3/sql/mysqld.cc:6280
    #7 0x5600e2f04df4 in main /10.3/sql/main.cc:25
    #8 0x7fd86b45609a in __libc_start_main ../csu/libc-start.c:308
 
0x60e000078d93 is located 115 bytes inside of 148-byte region [0x60e000078d20,0x60e000078db4)
allocated by thread T5 here:
    #0 0x7fd86bcaa330 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
    #1 0x5600e4f59880 in sf_malloc /10.3/mysys/safemalloc.c:118
    #2 0x5600e4f59de5 in sf_realloc /10.3/mysys/safemalloc.c:182
    #3 0x5600e4f293cf in my_realloc /10.3/mysys/my_malloc.c:166
    #4 0x7fd86109cb43 in ha_archive::fix_rec_buff(unsigned int) /10.3/storage/archive/ha_archive.cc:1218
    #5 0x7fd86109a142 in ha_archive::pack_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:926
    #6 0x7fd8610998ef in ha_archive::real_write_row(unsigned char*, azio_stream*) /10.3/storage/archive/ha_archive.cc:878
    #7 0x7fd86109b002 in ha_archive::write_row(unsigned char*) /10.3/storage/archive/ha_archive.cc:1056
    #8 0x5600e39d8201 in handler::ha_write_row(unsigned char*) /10.3/sql/handler.cc:6467
    #9 0x5600e3163dae in write_record(THD*, TABLE*, st_copy_info*) /10.3/sql/sql_insert.cc:2036
    #10 0x5600e315b49e in mysql_insert(THD*, TABLE_LIST*, List<Item>&, List<List<Item> >&, List<Item>&, List<Item>&, enum_duplicates, bool) /10.3/sql/sql_insert.cc:1072
    #11 0x5600e3207387 in mysql_execute_command(THD*) /10.3/sql/sql_parse.cc:4481
    #12 0x5600e321fd82 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /10.3/sql/sql_parse.cc:7839
    #13 0x5600e31f6421 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /10.3/sql/sql_parse.cc:1852
    #14 0x5600e31f2b5c in do_command(THD*) /10.3/sql/sql_parse.cc:1398
    #15 0x5600e35e2cbe in do_handle_one_connection(CONNECT*) /10.3/sql/sql_connect.cc:1403
    #16 0x5600e35e2576 in handle_one_connection /10.3/sql/sql_connect.cc:1308
    #17 0x5600e4d4512e in pfs_spawn_thread /10.3/storage/perfschema/pfs.cc:1869
    #18 0x7fd86bba7fa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
 
SUMMARY: AddressSanitizer: memcpy-param-overlap (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x3f105) 
==2173==ABORTING
----------SERVER LOG END-------------

Comment by Hirokazu Tanaka [ 2021-07-14 ]

I have seen the same problem with BLOB fields.

When running repair table on a table using the ARCHIVE storage engine, the data (first 4 bytes) of the BLOB field is corrupted.
This happens in 10.3 and later versions, and seems to be caused by the change from store to set_ptr in field.cc (Field_blob::unpack).

The workaround I came up with is as follows. This is a fix I made for version 10.4.19.
In the process of unpack during repair, offset ARCHIVE_ROW_HEADER_SIZE (4 bytes) and expand it to memory to prevent corruption.

// before(storage\archive\ha_archive.cc)
int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record)
{
 
 ・・・・・・・・
 
  if (fix_rec_buff(row_len))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_ASSERT(row_len <= record_buffer->length);
 
  read= azread(file_to_read, record_buffer->buffer, row_len, &error);
 
  if (read != row_len || error)
  {
    DBUG_RETURN(error ? HA_ERR_CRASHED_ON_USAGE : HA_ERR_WRONG_IN_RECORD);
  }
 
  /* Copy null bits */
  const uchar *ptr= record_buffer->buffer, *end= ptr+ row_len;
  
 ・・・・・・・・
 
}

// after(storage\archive\ha_archive.cc)
int ha_archive::unpack_row(azio_stream *file_to_read, uchar *record)
{
 
 ・・・・・・・・
 
  if (fix_rec_buff(row_len + ARCHIVE_ROW_HEADER_SIZE))
  {
    DBUG_RETURN(HA_ERR_OUT_OF_MEM);
  }
  DBUG_ASSERT(row_len + ARCHIVE_ROW_HEADER_SIZE <= record_buffer->length);
 
  read= azread(file_to_read, record_buffer->buffer + ARCHIVE_ROW_HEADER_SIZE, row_len, &error);
 
  if (read != row_len || error)
  {
    DBUG_RETURN(error ? HA_ERR_CRASHED_ON_USAGE : HA_ERR_WRONG_IN_RECORD);
  }
 
  /* Copy null bits */
  const uchar *ptr= record_buffer->buffer + ARCHIVE_ROW_HEADER_SIZE, *end= ptr+ row_len;
  
 ・・・・・・・・
 
}

Generated at Thu Feb 08 09:28:31 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.