[MDEV-30321] blob data corrupted by row_merge_write_blob_to_tmp_file() Created: 2023-01-02  Updated: 2023-02-09  Resolved: 2023-01-04

Status: Closed
Project: MariaDB Server
Component/s: Storage Engine - InnoDB
Affects Version/s: 10.7.6, 10.8.6, 10.9.4, 10.10.2
Fix Version/s: 10.11.3, 10.8.8, 10.9.6, 10.10.4

Type: Bug Priority: Critical
Reporter: Michael Roosz Assignee: Thirunarayanan Balathandayuthapani
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Duplicate
duplicates MDEV-29453 blob data corrupted by INSERT INTO Closed
Problem/Incident
is caused by MDEV-27318 SIGSEGV in row_merge_tuple_sort and A... Closed

 Description   

In

static dberr_t row_merge_write_blob_to_tmp_file()

the line

dberr_t err= os_file_write(
    IORequestWrite, "(bulk insert)", blob_file->fd,
    field->data, blob_file->offset * srv_page_size, len);

https://github.com/MariaDB/server/blob/11.0/storage/innobase/row/row0merge.cc#L1069

uses the file offset

blob_file->offset * srv_page_size

but the "* srv_page_size" part is not writen to the tuple field:

  uint64_t val= blob_file->offset;
  ...
  /* Write offset for next 8 bytes */
  mach_write_to_8(data + 8, val);

and the offset is also not updated for this:

blob_file->offset+= field->len;

thus when row_merge_copy_blob_from_file() reads the blob data, it reads from a wrong location

As I understand it the "* srv_page_size" make so sense here and should be removed.
Because it is multiplication it will work "correctly" if blob_file->offset is 0, so it seems to work for the first blob, and will be broken for all following blobs.

This is most likely the cause the issue I reported here:
https://jira.mariadb.org/browse/MDEV-29453

Here is a query which will trigger the bug:

SET UNIQUE_CHECKS=0;
SET FOREIGN_KEY_CHECKS=0;
 
/* Required condition: Tuple data size is greater than srv_sort_buf_size */
/* default: innodb_sort_buffer_size = 1048576 */
 
DROP DATABASE IF EXISTS `debug`;
CREATE DATABASE IF NOT EXISTS `debug`;
USE `debug`;
 
DROP TABLE IF EXISTS `d1`;
CREATE TABLE `d1` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `data` LONGBLOB NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
 
INSERT INTO `d1` VALUES 
  (DEFAULT, REPEAT('X', @@innodb_sort_buffer_size)),
  (DEFAULT, REPEAT('X', @@innodb_sort_buffer_size))
;
 
SELECT COUNT(*) AS nb_corrupted_rows FROM debug.d1 WHERE data != REPEAT('X', @@innodb_sort_buffer_size);

nb_corrupted_rows will be 1 on mariadb >= 10.7 and 0 for mariadb <= 10.6

pull request: https://github.com/MariaDB/server/pull/2400


Generated at Thu Feb 08 10:15:22 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.