Bug #105258 Table_map_event can not be parsed correctly if table name has mbchar and its len
Submitted: 19 Oct 2021 6:34 Modified: 3 Nov 2021 13:02
Reporter: Lujun Wang (OCA) Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Replication Severity:S3 (Non-critical)
Version:8.0, 8.0.26 OS:Any
Assigned to: CPU Architecture:Any
Tags: binlog event, regression

[19 Oct 2021 6:34] Lujun Wang
Description:
when table name has some mbchar(Chinese characters etc.) and total length is larger than 64 bytes, binlog generated from queries on this table can not be parsed correctly. 

It raises failure when parsing and checking table name length in function Table_map_event::Table_map_event(). Replication will be broken.

How to repeat:
create table `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` (id int);
insert into `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` value (1);

-- show binlog events will fail to parse the Table_map_event generated from the above insert query
show binlog events; 

Suggested fix:
diff --git a/libbinlogevents/src/rows_event.cpp b/libbinlogevents/src/rows_event.cpp
index 8d93752..5420875 100644
--- a/libbinlogevents/src/rows_event.cpp
+++ b/libbinlogevents/src/rows_event.cpp
@@ -69,13 +69,13 @@ Table_map_event::Table_map_event(const char *buf,
   /* Read the variable part of the event */
 
   READER_TRY_SET(m_dblen, read<uint8_t>);
-  if (m_dblen > 64 /* NAME_CHAR_LEN */)
+  if (m_dblen > NAME_LEN)
     READER_THROW("Database name length too long.")
   ptr_dbnam = READER_TRY_CALL(ptr, m_dblen + 1);
   m_dbnam = std::string(ptr_dbnam, m_dblen);
 
   READER_TRY_SET(m_tbllen, read<uint8_t>);
-  if (m_tbllen > 64 /* NAME_CHAR_LEN */)
+  if (m_tbllen > NAME_LEN)
     READER_THROW("Table name length too long.")
   ptr_tblnam = READER_TRY_CALL(ptr, m_tbllen + 1);
   m_tblnam = std::string(ptr_tblnam, m_tbllen);
[19 Oct 2021 6:57] MySQL Verification Team
Hello Larry Wang,

Thank you for the report and test case.
Verified as described.

regards,
Umesh
[19 Oct 2021 6:58] MySQL Verification Team
- 8.0.26

rm -rf 105258/
bin/mysqld --initialize-insecure --basedir=$PWD --datadir=$PWD/105258 --log-error-verbosity=3
bin/mysqld --no-defaults --basedir=$PWD --datadir=$PWD/105258 --core-file --socket=/tmp/mysql_ushastry.sock  --port=3306 --log-error=$PWD/105258/log.err --log-error-verbosity=3  --secure-file-priv=/tmp/ 2>&1 &

 bin/mysql -uroot -S /tmp/mysql_ushastry.sock
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7
Server version: 8.0.26 MySQL Community Server - GPL

Copyright (c) 2000, 2021, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> use test
Database changed
mysql> create table `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` (id int);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` value (1);
Query OK, 1 row affected (0.00 sec)

mysql> -- show binlog events will fail to parse the Table_map_event generated from the above insert query
mysql> show binlog events;
ERROR 1220 (HY000): Error when executing command SHOW BINLOG EVENTS: Found invalid event in binary log
mysql>
[19 Oct 2021 7:01] MySQL Verification Team
-- looks like a regression to me in 8.0.x
-- 5.7.35 not affected

rm -rf 105258/
bin/mysqld --initialize-insecure --basedir=$PWD --datadir=$PWD/105258 --log-error-verbosity=3
bin/mysqld --no-defaults --basedir=$PWD --datadir=$PWD/105258 --core-file --socket=/tmp/mysql_ushastry.sock --port=3306 --log-error=$PWD/105258/log.err --log-error-verbosity=3 --secure-file-priv=""  --performance-schema=ON --log-bin --server-id=1 2>&1 &

 bin/mysql -uroot -S /tmp/mysql_ushastry.sock
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.35-log MySQL Community Server (GPL)

Copyright (c) 2000, 2021, 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.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database test;
Query OK, 1 row affected (0.00 sec)

mysql> use test
Database changed
mysql> create table `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` (id int);
Query OK, 0 rows affected (0.02 sec)

mysql> insert into `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` value (1);
Query OK, 1 row affected (0.01 sec)

mysql>  -- show binlog events will fail to parse the Table_map_event generated from the above insert query
mysql> show binlog events;
+------------------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| Log_name                     | Pos | Event_type     | Server_id | End_log_pos | Info                                                                                                                                               |
+------------------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
| support-cluster03-bin.000001 |   4 | Format_desc    |         1 |         123 | Server ver: 5.7.35-log, Binlog ver: 4                                                                                                              |
| support-cluster03-bin.000001 | 123 | Previous_gtids |         1 |         154 |                                                                                                                                                    |
| support-cluster03-bin.000001 | 154 | Anonymous_Gtid |         1 |         219 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                                               |
| support-cluster03-bin.000001 | 219 | Query          |         1 |         313 | create database test                                                                                                                               |
| support-cluster03-bin.000001 | 313 | Anonymous_Gtid |         1 |         378 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                                               |
| support-cluster03-bin.000001 | 378 | Query          |         1 |         586 | use `test`; create table `t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十` (id int)                                     |
| support-cluster03-bin.000001 | 586 | Anonymous_Gtid |         1 |         651 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS'                                                                                                               |
| support-cluster03-bin.000001 | 651 | Query          |         1 |         723 | BEGIN                                                                                                                                              |
| support-cluster03-bin.000001 | 723 | Table_map      |         1 |         876 | table_id: 108 (test.t_测试中文表名一二三四五六七八九十一二三四五六七八九十一二三四五六七八九十)                                                    |
| support-cluster03-bin.000001 | 876 | Write_rows     |         1 |         916 | table_id: 108 flags: STMT_END_F                                                                                                                    |
| support-cluster03-bin.000001 | 916 | Xid            |         1 |         947 | COMMIT /* xid=9 */                                                                                                                                 |
+------------------------------+-----+----------------+-----------+-------------+----------------------------------------------------------------------------------------------------------------------------------------------------+
11 rows in set (0.00 sec)
[19 Oct 2021 7:09] MySQL Verification Team
Thank you very much for your patch contribution, we appreciate it!

In order for us to continue the process of reviewing your contribution to MySQL, please send us a signed copy of the Oracle Contributor Agreement (OCA) as outlined in http://www.oracle.com/technetwork/community/oca-486395.html

Signing an OCA needs to be done only once and it's valid for all other Oracle governed Open Source projects as well.

Getting a signed/approved OCA on file will help us facilitate your contribution - this one, and others in the future.  

Please let me know, if you have any questions.

Thank you for your interest in MySQL.
[27 Oct 2021 9:08] Lujun Wang
Hi, I am already under tencent OCA.
[27 Oct 2021 9:09] Lujun Wang
bugfix patch file for mbchar bugfix

Attachment: mb_bugfix.patch (application/octet-stream, text), 838 bytes.

[27 Oct 2021 9:55] MySQL Verification Team
Thank you, please ensure to re-send the patch via "contribution" tab. Otherwise we would not be able to accept it.

regards,
Umesh
[27 Oct 2021 9:57] Lujun Wang
bugfix patch file for mbchar bugfix

(*) I confirm the code being submitted is offered under the terms of the OCA, and that I am authorized to contribute it.

Contribution: mb_bugfix.patch (application/octet-stream, text), 838 bytes.

[3 Nov 2021 12:52] Pedro Gomes
Posted by developer:
 
Bug#105258 is a duplicate of Bug#104798

While the reported failures are slightly different, but are both about how we incorrectly check the table name in bytes and not in length of characters.
[3 Nov 2021 13:01] Pedro Gomes
Hi Larry

Thanks for your contribution.
We in the development team went another way and we will remove the check altogether. It is our opinion that this logic check does not belong in this layer. 

I hope this doesn't discourage you from proposing other fixes in the future.

Also, this bug will be marked as a duplicated of Bug#104798, please refer to the bug.