Bug #119667 Assertion failure ddl0buffer.cc:197 with innodb-ddl-threads=4 + O_DIRECT
Submitted: 13 Jan 11:42 Modified: 26 Jan 14:07
Reporter: Jacob Ding Email Updates:
Status: Open Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S2 (Serious)
Version:9.4.0 OS:Ubuntu (22.04)
Assigned to: CPU Architecture:x86 (x86_64)
Tags: assertion failure, DDL, innodb-ddl-threads, O_DIRECT

[13 Jan 11:42] Jacob Ding
Description:
When replaying a minimal SQL script extracted from
mysql-test/suite/innodb_zip/t/prefix_index_liftedlimit.test,
mysqld debug build asserts at storage/innobase/ddl/ddl0buffer.cc:197
(ptr + rec_size <= bounds.second) during Key_sort_buffer::serialize.
Originally observed with
--innodb-ddl-threads=4 --innodb-flush-method=O_DIRECT
Additional tests show the same crash (identical stack) also occurs with
--innodb-ddl-threads=1 --innodb-flush-method=O_DIRECT
and
--innodb-ddl-threads=4 --innodb-flush-method=fsync
and
--innodb-ddl-threads=1 --innodb-flush-method=fsync
This indicates an internal boundary check error inside the parallel DDL
key-sort buffer serialization code path, independent of the specific
non-default parameter pair first used.

the stacktrace are shown below:
```
2026-01-13T11:35:43.813677Z 0 [System] [MY-010931] [Server] /usr/local/mysql/bin/mysqld: ready for connections. Version: '9.4.0-debug'  socket: '/tmp/mysql.sock'  port: 3306  Source distribution.
2026-01-13T11:35:44.290093Z 10 [ERROR] [MY-013183] [InnoDB] Assertion failure: ddl0buffer.cc:197:ptr + rec_size <= bounds.second thread 140126445360704
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/9.4/en/forcing-innodb-recovery.html
InnoDB: about forcing recovery.
2026-01-13T11:35:44Z UTC - mysqld got signal 6 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
BuildID[sha1]=a86b0c4acbd4b43cf7c902fb975416e9f8588602
Thread pointer: 0x7f71e8013090
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 = 7f73646f6998 thread_stack 0x100000
 #0 0x55a0ab108f6b print_fatal_signal at /usr/src/mysql-server/sql/signal_handler.cc:321
 #1 0x55a0ab1092fd _Z15my_server_abortv at /usr/src/mysql-server/sql/signal_handler.cc:449
 #2 0x55a0ac7acb7f _Z8my_abortv at /usr/src/mysql-server/mysys/my_init.cc:267
 #3 0x55a0acc3488b _Z23ut_dbg_assertion_failedPKcS0_m at /usr/src/mysql-server/storage/innobase/ut/ut0dbg.cc:100
 #4 0x55a0acfd7b23 _ZN3ddl15Key_sort_buffer9serializeESt4pairIPhmESt8functionIF7dberr_tS3_EE at /usr/src/mysql-server/storage/innobase/ddl/ddl0buffer.cc:197
 #5 0x55a0acfe2006 _ZN3ddl7Builder12bulk_add_rowERNS_6CursorERNS_3RowEmOSt8functionIF7dberr_tvEE at /usr/src/mysql-server/storage/innobase/ddl/ddl0builder.cc:1572
 #6 0x55a0acfe21ad _ZN3ddl7Builder7add_rowERNS_6CursorERNS_3RowEmOSt8functionIF7dberr_tvEE at /usr/src/mysql-server/storage/innobase/ddl/ddl0builder.cc:1603
 #7 0x55a0aceb9bf7 operator() at /usr/src/mysql-server/storage/innobase/ddl/ddl0par-scan.cc:237
 #8 0x55a0aceb9fc2 operator() at /usr/src/mysql-server/storage/innobase/ddl/ddl0par-scan.cc:315
 #9 0x55a0acebc7ef __invoke_impl<dberr_t, ddl::Parallel_cursor::scan(ddl::Builders&)::<lambda(Thread_ctx*)>&, Parallel_reader::Thread_ctx*> at /usr/include/c++/11/bits/invoke.h:61
 #10 0x55a0acebbffa __invoke_r<dberr_t, ddl::Parallel_cursor::scan(ddl::Builders&)::<lambda(Thread_ctx*)>&, Parallel_reader::Thread_ctx*> at /usr/include/c++/11/bits/invoke.h:114
 #11 0x55a0acebb93e _M_invoke at /usr/include/c++/11/bits/std_function.h:290
 #12 0x55a0acb143c4 <unknown>
 #13 0x55a0acb0e871 _ZN15Parallel_reader6workerEPNS_10Thread_ctxE at /usr/src/mysql-server/storage/innobase/row/row0pread.cc:1081
 #14 0x55a0acb1b41a _ZSt13__invoke_implIvM15Parallel_readerFvPNS0_10Thread_ctxEEPS0_JS2_EET_St21__invoke_memfun_derefOT0_OT1_DpOT2_ at /usr/include/c++/11/bits/invoke.h:74
 #15 0x55a0acb1b38c _ZSt8__invokeIM15Parallel_readerFvPNS0_10Thread_ctxEEJPS0_S2_EENSt15__invoke_resultIT_JDpT0_EE4typeEOS7_DpOS8_ at /usr/include/c++/11/bits/invoke.h:96
 #16 0x55a0acb1b32f _ZSt6invokeIM15Parallel_readerFvPNS0_10Thread_ctxEEJPS0_S2_EENSt13invoke_resultIT_JDpT0_EE4typeEOS7_DpOS8_ at /usr/include/c++/11/functional:97
 #17 0x55a0acb1b27b _ZN15Detached_threadclIM15Parallel_readerFvPNS1_10Thread_ctxEEJPS1_S3_EEEvOT_DpOT0_ at /usr/src/mysql-server/storage/innobase/include/os0thread-create.h:191
 #18 0x55a0acb1b112 _ZSt13__invoke_implIv15Detached_threadJM15Parallel_readerFvPNS1_10Thread_ctxEEPS1_S3_EET_St14__invoke_otherOT0_DpOT1_ at /usr/include/c++/11/bits/invoke.h:61
 #19 0x55a0acb1b011 _ZSt8__invokeI15Detached_threadJM15Parallel_readerFvPNS1_10Thread_ctxEEPS1_S3_EENSt15__invoke_resultIT_JDpT0_EE4typeEOS8_DpOS9_ at /usr/include/c++/11/bits/invoke.h:96
 #20 0x55a0acb1aef0 _ZNSt6thread8_InvokerISt5tupleIJ15Detached_threadM15Parallel_readerFvPNS3_10Thread_ctxEEPS3_S5_EEE9_M_invokeIJLm0ELm1ELm2ELm3EEEEvSt12_Index_tupleIJXspT_EEE at /usr/include/c++/11/bits/std_thread.h:259
 #21 0x55a0acb1ae3d _ZNSt6thread8_InvokerISt5tupleIJ15Detached_threadM15Parallel_readerFvPNS3_10Thread_ctxEEPS3_S5_EEEclEv at /usr/include/c++/11/bits/std_thread.h:266
 #22 0x55a0acb1addb _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJ15Detached_threadM15Parallel_readerFvPNS4_10Thread_ctxEEPS4_S6_EEEEE6_M_runEv at /usr/include/c++/11/bits/std_thread.h:211
 #23 0x7f73c4936252 <unknown>
 #24 0x7f73c45beac2 <unknown>
 #25 0x7f73c464fa73 <unknown>
 #26 0xffffffffffffffff <unknown>
```

How to repeat:
Build MySQL 9.4.0 with -DWITH_DEBUG=ON.
Initialize a clean data directory.
Start mysqld with either
a) --innodb-ddl-threads=4 --innodb-flush-method=O_DIRECT  (original)
b) --innodb-ddl-threads=1 --innodb-flush-method=O_DIRECT  (also crashes)
c) --innodb-ddl-threads=4 --innodb-flush-method=fsync      (also crashes)
d) --innodb-ddl-threads=1 --innodb-flush-method=fsync    (also crashes)
Execute the attached SQL script prefix_index_liftedlimit_extract.sql.
Server aborts with assertion failure shown in mysqld.err.

```
CREATE DATABASE IF NOT EXISTS `mtr_repro_prefix_index`;
USE `mtr_repro_prefix_index`;

CREATE TABLE worklog5743 ( col_1_varchar VARCHAR (4000) , col_2_varchar VARCHAR (4000) , PRIMARY KEY `prefix_primary` (col_1_varchar(3072)) ) charset latin1 ROW_FORMAT=DYNAMIC, engine = innodb;

INSERT INTO worklog5743 VALUES(REPEAT("a", 4000) , REPEAT("o", 4000));

CREATE INDEX prefix_idx ON worklog5743(col_1_varchar (3072));

INSERT INTO worklog5743 VALUES(REPEAT("b", 4000) , REPEAT("p", 4000));

ALTER TABLE worklog5743 DROP PRIMARY KEY;

DROP INDEX prefix_idx ON worklog5743;

ALTER TABLE worklog5743 ADD PRIMARY KEY (col_1_varchar(3072));
```
[15 Jan 12:44] MySQL Verification Team
For some reason I couldn't reproduce this:

Run server:
$ ./bin/mysqld-debug --no-defaults --basedir=. --datadir=data --port=3333 --socket=/tmp/2222.sock --innodb-ddl-threads=1 --innodb-flush-method=O_DIRECT --console
2026-01-15T12:41:41.899996Z 0 [System] [MY-015015] [Server] MySQL Server - start.
2026-01-15T12:41:42.093247Z 0 [System] [MY-010116] [Server] /tmp/mysql-commercial-9.4.0-linux-glibc2.17-x86_64/bin/mysqld-debug (mysqld 9.4.0-commercial-debug) starting as process 16043
2026-01-15T12:41:42.093268Z 0 [System] [MY-015590] [Server] MySQL Server has access to 16 logical CPUs.
2026-01-15T12:41:42.093287Z 0 [System] [MY-015590] [Server] MySQL Server has access to 126064812032 bytes of physical memory.
2026-01-15T12:41:42.104132Z 1 [System] [MY-013576] [InnoDB] InnoDB initialization has started.
2026-01-15T12:41:42.714639Z 1 [System] [MY-013577] [InnoDB] InnoDB initialization has ended.
2026-01-15T12:41:43.574816Z 0 [ERROR] [MY-011300] [Server] Plugin mysqlx reported: 'Setup of socket: '/tmp/mysqlx.sock' failed, can't open lock file /tmp/mysqlx.sock.lock'
2026-01-15T12:41:43.836707Z 0 [Warning] [MY-010068] [Server] CA certificate ca.pem is self signed.
2026-01-15T12:41:43.836768Z 0 [System] [MY-013602] [Server] Channel mysql_main configured to support TLS. Encrypted connections are now supported for this channel.
2026-01-15T12:41:43.841598Z 0 [Warning] [MY-011810] [Server] Insecure configuration for --pid-file: Location '/export/home/tmp' in the path is accessible to all OS users. Consider choosing a different directory.
2026-01-15T12:41:43.986487Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060
2026-01-15T12:41:43.986677Z 0 [System] [MY-010931] [Server] /tmp/mysql-commercial-9.4.0-linux-glibc2.17-x86_64/bin/mysqld-debug: ready for connections. Version: '9.4.0-commercial-debug'  socket: '/tmp/2222.sock'  port: 3333  MySQL Enterprise Server - Commercial - Debug.

$ mysql -uroot -h127.0.0.1 -P3333  -v
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 221
Server version: 9.4.0-commercial-debug MySQL Enterprise Server - Commercial - Debug

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Reading history-file /home/sbester/.mysql_history
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> source g.sql
--------------
drop database if exists `mtr_repro_prefix_index`
--------------

Query OK, 1 row affected (0.03 sec)

--------------
CREATE DATABASE IF NOT EXISTS `mtr_repro_prefix_index`
--------------

Query OK, 1 row affected (0.01 sec)

Database changed
--------------
CREATE TABLE worklog5743 ( col_1_varchar VARCHAR (4000) , col_2_varchar VARCHAR (4000) , PRIMARY KEY `prefix_primary` (col_1_varchar(3072)) ) charset latin1 ROW_FORMAT=DYNAMIC, engine = innodb
--------------

Query OK, 0 rows affected (0.03 sec)

--------------
INSERT INTO worklog5743 VALUES(REPEAT("a", 4000) , REPEAT("o", 4000))
--------------

Query OK, 1 row affected (0.00 sec)

--------------
CREATE INDEX prefix_idx ON worklog5743(col_1_varchar (3072))
--------------

Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

--------------
INSERT INTO worklog5743 VALUES(REPEAT("b", 4000) , REPEAT("p", 4000))
--------------

Query OK, 1 row affected (0.01 sec)

--------------
ALTER TABLE worklog5743 DROP PRIMARY KEY
--------------

Query OK, 2 rows affected (0.09 sec)
Records: 2  Duplicates: 0  Warnings: 0

--------------
DROP INDEX prefix_idx ON worklog5743
--------------

Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

--------------
ALTER TABLE worklog5743 ADD PRIMARY KEY (col_1_varchar(3072))
--------------

Query OK, 0 rows affected (0.08 sec)
Records: 0  Duplicates: 0  Warnings: 0
[16 Jan 6:23] MySQL Verification Team
BTW, if you can try 9.5.0 also, it will be good.

However I've followed your exact steps on a ubuntu 22.04 VM (not docker) and still don't see any problem on 9.4.0-debug.

mysql> select @@global.innodb_flush_method,@@global.innodb_ddl_threads,version();
+------------------------------+-----------------------------+-------------+
| @@global.innodb_flush_method | @@global.innodb_ddl_threads | version()   |
+------------------------------+-----------------------------+-------------+
| O_DIRECT                     |                           4 | 9.4.0-debug |
+------------------------------+-----------------------------+-------------+
1 row in set (0.001 sec)

mysql>
mysql> CREATE DATABASE IF NOT EXISTS `mtr_repro_prefix_index`;
Query OK, 1 row affected (0.017 sec)

....

mysql>
mysql> ALTER TABLE worklog5743 ADD PRIMARY KEY (col_1_varchar(3072));
Query OK, 0 rows affected (0.189 sec)
Records: 0  Duplicates: 0  Warnings: 0

2026-01-16T06:16:51.288199Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /tmp/mysqlx.sock
2026-01-16T06:16:51.288291Z 0 [System] [MY-010931] [Server] /usr/global/support/sbester/bug119667/my/bin/mysqld: ready for connections. Version: '9.4.0-debug'  socket: '/tmp/mysql.sock'  port: 3306  Source distribution.

no crash.

Extra info:
-------------
$ lsblk -o NAME,PHY-SeC,SIZE
NAME    PHY-SEC   SIZE
loop0       512 104.2M
loop1       512  55.5M
loop2       512  63.8M
loop3       512  89.4M
loop4       512 100.4M
loop5       512  49.3M
loop6       512   105M
loop7       512  55.5M
loop8       512  63.8M
loop9       512  91.4M
sda        4096   125G
├─sda1     4096 124.9G
├─sda14    4096     4M
└─sda15    4096   106M

$ sudo blockdev --getbsz /dev/sda
4096
$ sudo blockdev --getss /dev/sda
512
$ sudo blockdev --getpbsz /dev/sda
4096

$ sudo fdisk -l /dev/sda
Disk /dev/sda: 125 GiB, 134217728000 bytes, 262144000 sectors
Disk model: BlockVolume
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 1048576 bytes
Disklabel type: gpt
Disk identifier: C419A41F-2861-4103-9CFA-3854CDD8F03F

Device      Start       End   Sectors   Size Type
/dev/sda1  227328 262143966 261916639 124.9G Linux filesystem
/dev/sda14   2048     10239      8192     4M BIOS boot
/dev/sda15  10240    227327    217088   106M EFI System

Partition table entries are not in disk order.

$ stat -f /tmp
  File: "/tmp"
    ID: 95a394e5df7a87ec Namelen: 255     Type: ext2/ext3
Block size: 4096       Fundamental block size: 4096
Blocks: Total: 31709340   Free: 28741742   Available: 28737646
Inodes: Total: 16128000   Free: 15801944

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.5 LTS
Release:        22.04
Codename:       jammy
[16 Jan 6:31] MySQL Verification Team
I'll try docker next and see if it reproduces there.
[16 Jan 6:52] Jacob Ding
I tried, and found that the parameters are not actually needed to trigger the assertion failure following the commands acctually...@@global.innodb_flush_method | @@global.innodb_ddl_threads
Sorry for the inconvenience. 
And it also worked for 9.5.0.
[16 Jan 6:55] MySQL Verification Team
I've found similar bugfix in the past:

https://github.com/search?q=repo%3Amysql%2Fmysql-server+36342792&type=commits
[16 Jan 7:06] Jacob Ding
I analyzed the stack trace and the commit you linked. You are absolutely right—they are highly similar.

Location: My crash occurs in ddl::Key_sort_buffer::serialize called by bulk_add_row, which matches the context of Bug#36342792 exactly.

Logic: The assertion failure ptr + rec_size <= bounds.second explicitly indicates a write past the buffer end, which is the exact symptom described in that bug report ("aligned past end of buffer").

However, here is the critical point: I am reproducing this on the latest 9.5.0 (and 9.4.0) build, which certainly includes the fix from Bug#36342792.

This indicates that the previous fix (Change-Id: I607...) was likely incomplete or did not cover the specific edge case triggered by my test steps. The condition to "free up space in the buffer" (mentioned in the fix) might not be triggering correctly in this specific scenario, leading to the assertion failure.

So, this report likely represents a scenario that bypassed the previous fix.
[16 Jan 8:21] MySQL Verification Team
I've tried in a docker too, still couldn't reproduce it.

mysql> ALTER TABLE worklog5743 ADD PRIMARY KEY (col_1_varchar(3072));
Query OK, 0 rows affected (0.294 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 
mysql> select version();
+-------------+
| version()   |
+-------------+
| 9.5.0-debug |
+-------------+
1 row in set (0.006 sec)

mysql> select @@innodb_ddl_threads,@@innodb_flush_method;
+----------------------+-----------------------+
| @@innodb_ddl_threads | @@innodb_flush_method |
+----------------------+-----------------------+
|                    4 | O_DIRECT              |
+----------------------+-----------------------+
1 row in set (0.001 sec)
[16 Jan 9:05] MySQL Verification Team
I've found another similar issue that was actually fixed in 9.5.0:

https://github.com/search?q=repo%3Amysql%2Fmysql-server+37882398&type=commits

so checking with the devs about this one.
[26 Jan 12:53] Jacob Ding
Sorry for the late reply — I’ve been tied up for the last ~10 days.

Quick update / context:
- The source tree I’m testing is exactly mysql-9.4.0 at commit/tag `b79ac1111737174c1b36ab5f63275f0191c000dc`.
- I noticed that this commit contains the fix for Bug#37882398 (assertion in `ddl0file-reader.cc:193`) related to DDL chunk sizes / 4KB sector alignment and input buffer limits (as described in the commit message).

Why I’m following up:
- My crash is a similar InnoDB debug assertion, but in a different location:
  `Assertion failure: ddl0buffer.cc:197: ptr + rec_size <= bounds.second`
  top frame: `ddl::Key_sort_buffer::serialize()` during `ALTER TABLE ... ADD PRIMARY KEY (col_1_varchar(3072))`.
- This suggests there may still be an unhandled edge case in the DDL buffer / chunk / input-buffer sizing logic (even though 9.4.0 already includes the 37882398 fix), or a closely related regression triggered by the same scenario.

New evidence uploaded:
I uploaded a tarball of my `repro_out_manual/` output directory from a clean Ubuntu 22.04 based environment. It should be a complete evidence set to compare with the non-repro reports. It includes:
- `mysqld.err` (BuildID + assertion + full backtrace)
  - BuildID[sha1]=`71738c4ea7bf644be5fd56e308c93e8359011ec6`
  - signature: `ddl0buffer.cc:197` + SIGABRT
- `collect.pre.txt` / `collect.mid.txt` (server variables snapshot, including `@@innodb_ddl_threads`, `@@innodb_flush_method`, `@@innodb_use_native_aio`, etc.)
- `show_create_table.collect.mid.txt` (schema right before the crashing `ALTER`, after dropping PK and the secondary index)
- `import.stdout` / `import.stderr`

Repro summary:
- Execute the attached `min_repro_prefix_index_liftedlimit.sql` (from MTR). The final statement triggers the crash:
  `ALTER TABLE worklog5743 ADD PRIMARY KEY (col_1_varchar(3072));`
- The crash reproduces with `innodb_ddl_threads=4` and also with `innodb_ddl_threads=1`, and also with `--no-defaults` in my environment.

If helpful, I can also share the exact docker image / harness used to generate `repro_out_manual/` to ensure a 1:1 environment.
[26 Jan 14:07] Jacob Ding
Update: I re-checked reproducibility across environments.
In my docker repro environment (Ubuntu 22.04 container, MySQL 9.4.0-debug, BuildID 71738c4ea7bf644be5fd56e308c93e8359011ec6), the split repro still consistently crashes with the same debug assertion:
storage/innobase/ddl/ddl0buffer.cc:197 (ddl::Key_sort_buffer::serialize()), followed by mysqld got signal 6.
The full logs and evidence are attached in repro_out_manual (includes mysqld.err, collect.pre/mid/post.txt, and SHOW CREATE TABLE snapshots).
On a separate Ubuntu 22.04 PVE VM, running the same SQL (min_repro_prefix_index_liftedlimit.sql) did NOT reproduce after 200 iterations (loop runner drops/recreates worklog5743 each time). tmpdir=/tmp on ext4; client connects via /tmp/mysql.sock.
Next steps I’m trying: increasing data volume (more rows) and sweeping innodb_sort_buffer_size to see if the trigger is boundary/probabilistic. If you have any recommended knobs to force the DDL sort/merge path that hits this assertion, I can test them.