Description:
We met a assertion failure as follows:
[MY-013183] [InnoDB] Assertion failure: filOftl.c:7835:file->size - page no >= (byte_offset + std::max(static_cast<uint32_t>(len), type.get_original_size()) + (page_size.physical() - 1)) / page_size.physical() thread 13974781838720
InnoDB: We intentionally generate a memory trap.
InnoDB: Submit a detailed bug report to http://bugs.mysql.com.
InnoDB: If you get repeated assertion failures or crashes, even
InnoDB: immediately after the mysqld startup, there may be
InnoDB: corruption in the InnoDB tablespace. Please refer to
InnoDB: http://dev.mysql. com/doc/refman/8.0/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
2025-10-17T03:22:12Z UTC - mysqld got signal 6 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
BuildID[sha1]=cbe9b32091b6353329a78dc19926c71f26dc9990
Thread pointer: 0x7f199c803000
Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong..
stack bottom = 7f1993128f20 thread stack 0x100000
/usr/bin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x3d) [0x235d94d]
/usr/bin/mysqld(print_fatal_signal(int)+0x37f) [0x1216edf]
/usr/bin/mysqld(my_server_abort()+0x7e) [0x121702e]
/usr/bin/mysqld(my_abort( )+0xa) [0x2357b1a]
/usr/bin/mysqld(ut_dbg_assertion_failed(char const*, char const*, unsigned long)+0x32f) [0x261e24f]
/usr/bin/mysqld(Fil_shard::do_io(IORequest const&, bool, page_id_t const&, page_size_t const&, unsigned long, unsigned long, void*, void*)+0xb98) [0x276d478]
/usr/bin/mysqld(fil_io(IORequest const&, bool, page_id_t const&, page_size_t const&, unsigned long, unsigned long, void*, void*)+0x70) [0x276d590]
/usr/bin/mysqld(Double_write::write_to_datafile(buf page_ t const*, bool, file::Block const*)+0x9e) [0x26847de]
/usr/bin/mysqld(dblwr::write(buf_flush_t, buf_page_t*, bool)+0xc3) [0x2692f03]
/usr/bin/mysqld(buf_flush_page(buf_pool_t*, buf_page_t*, buf_flush_t, bool)+0x26f) [0x2697daf]
/usr/bin/mysqld() [0x269a7f3]
/usr/bin/mysqld(buf_flush_do_batch(buf_pool_t*, buf_flush_t, unsigned long, unsigned long, unsigned long*)+0x39b) [0x269af8b]
/usr/bin/mysqld() [0x269c1d7]
/usr/bin/mysqld() [0x269cb55]
/usr/bin/mysqld(void Detached_thread::operator()<void (*)()>(void (*&&)())+0xc2) [0x250c4f2]
/usr/bin/mysqld() [0x31464d4]
/lib64/libpthread.so.0(+0x7ea5) [0x7f19b7a13ea5]
/lib64/libc. so.6(clone+0x6d) [0x7f19b67038dd]
Trying to get some varables.
Some pointers may be invalid and cause the dump to abort.
Query (0): Connection ID (thread ID): 0
Status: NOT KILLED
How to repeat:
Apply this patch and run mtr test below:
```
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index 42f8a81a8c3..cb8aa0957cc 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -4673,6 +4673,12 @@ bool Fil_shard::space_truncate(space_id_t space_id, page_no_t size_in_pages) {
return false;
}
+ DBUG_EXECUTE_IF("before_bump_version", {
+ ib::info() << "hang at before_bump_version";
+ sleep(10);
+ ib::info() << "before_bump_version go";
+ };);
+
mutex_acquire();
/* Step-2: Mark the tablespace pages in the buffer pool as stale by bumping
@@ -4711,6 +4717,12 @@ bool Fil_shard::space_truncate(space_id_t space_id, page_no_t size_in_pages) {
mutex_release();
+ DBUG_EXECUTE_IF("after_truncate", {
+ ib::info() << "hang at after_truncate";
+ sleep(10);
+ ib::info() << "after_truncate go";
+ };);
+
return success;
#else
/* Truncating a tablespace is not supported for MEB. */
@@ -7818,6 +7830,20 @@ dberr_t Fil_shard::do_io(const IORequest &type, bool sync,
mutex_release();
+ DBUG_EXECUTE_IF("before_io_check", {
+ if (req_type.is_write()) {
+ ib::info() << "hang at before_io_check";
+ usleep(50 * 1000);
+ ib::info() << "before_io_check go, space: " << page_id.space()
+ << ", page no: " << page_id.page_no()
+ << ", file size: " << file->size
+ << ", (file->size - page_no): " << file->size - page_no
+ << ", ((byte_offset + std::max(static_cast<uint32_t>(len), type.get_original_size()) + (page_size.physical() - 1)) / page_size.physical()): "
+ << (byte_offset + std::max(static_cast<uint32_t>(len), type.get_original_size()) + (page_size.physical() - 1)) / page_size.physical();
+ }
+ };);
+
+
DEBUG_SYNC_C("innodb_fil_do_io_prepared_io_with_no_mutex");
ut_a(page_size.is_compressed() ||
```
```
--source include/have_debug_sync.inc
--echo # Establish session con1 (user=root)
connect (con1,localhost,root,,);
create temporary table t1 (a int, b blob);
let $i = 0;
while ($i < 1000)
{
insert into t1 values (1, repeat("a", 10000));
inc $i;
}
set global debug = "+d,before_io_check";
set debug = "+d,before_bump_version,after_truncate";
disconnect con1;
sleep 20;
connection default;
set global debug = "-d,before_io_check";
```
In the error log, we can found the following messages:
```
[MY-011825] [InnoDB] hang at before_io_check
[MY-011825] [InnoDB] before_bump_version go
[MY-011825] [InnoDB] hang at after_truncate
[MY-011825] [InnoDB] before_io_check go, space: 4243767289, page no: 748, file size: 5, (file->size - page_no): 4294966553, ((byte_offset + std::max(static_cast<uint32_t>(len), type.get_original_size()) + (page_size.physical() - 1)) / page_size.physical()): 1
[MY-011825] [InnoDB] hang at before_io_check
```
We can see that, the temporary table (table space id: 4243767289) was truncated to 5 pages. However, the write operation targeted page number 748, indicating that the dirty page flushing process for this temporary table may have exceeded the bounds of the ibt file.
Since both file->size and the page_no are defined as unsigned int types, if the file->size and page_no are equal, the assertion failure would be triggered.
Additionally, we suspect a possible typo in the assertion logic. The assertion appears to test only for equality (file->size == page_no), whereas it likely intended to validate that page_no is within the valid range of the file (i.e., page_no < file->size).
Suggested fix:
Plan 1:
The out-of-bound write operation on the .ibt file might not be harmful. Therefore, we could modify the assertion to only enforce the page_no < file->sizecheck for read requests.
Plan 2:
Currently, space->stop_new_ops likely blocks new read I/O when a tablespace is being truncated or deleted. We should extend this mechanism to also reject write requests once the tablespace size is reduced. This would prevent flushing dirty pages beyond the new file boundary.