Bug #102477 When one row of result exceeded 4GB, the server does not response appropriately
Submitted: 4 Feb 2021 10:54 Modified: 4 Feb 2021 14:44
Reporter: Qilu Wei Email Updates:
Status: Unsupported Impact on me:
None 
Category:MySQL Server Severity:S3 (Non-critical)
Version: OS:Linux
Assigned to: CPU Architecture:Any

[4 Feb 2021 10:54] Qilu Wei
Description:
create table t1 (a longblob);
insert into t1 values (load_file("../../mysql64_linux.tar.gz"));
-- make sure the length of one row of result exceeded 4GB.
select a,a,a,a,a,a,a,a,a,a,a from t1;

1. When the server is compiled as debug, the server failed for DBUG_ASSERT:

virtual bool Sql_cmd_dml::execute(THD*): Assertion `thd->is_error() || thd->killed' failed.
06:31:03 UTC - mysqld got signal 6 ;
Most likely, you have hit a bug, but this error can also be caused by malfunctioning hardware.
Thread pointer: 0x4ea0e800
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 = 7fb49c7abba8 thread_stack 0x46000
/home/wqldb_8018/bin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x43) [0x4c35aa4]
/home/wqldb_8018/bin/mysqld(handle_fatal_signal+0x2bf) [0x38e6be6]
/usr/lib64/libpthread.so.0(+0xf5e0) [0x7fb49c0d25e0]
/usr/lib64/libc.so.6(gsignal+0x37) [0x7fb49a21e1f7]
/usr/lib64/libc.so.6(abort+0x148) [0x7fb49a21f8e8]
/usr/lib64/libc.so.6(+0x2e266) [0x7fb49a217266]
/usr/lib64/libc.so.6(+0x2e312) [0x7fb49a217312]
/home/wqldb_8018/bin/mysqld(Sql_cmd_dml::execute(THD*)+0x699) [0x372dc39]
/home/wqldb_8018/bin/mysqld(mysql_execute_command(THD*, bool)+0x5c69) [0x36c9833]
/home/wqldb_8018/bin/mysqld(mysql_parse(THD*, Parser_state*)+0x798) [0x36cca0b]
/home/wqldb_8018/bin/mysqld(dispatch_command(THD*, COM_DATA const*, enum_server_command)+0x1609) [0x36c0768]
/home/wqldb_8018/bin/mysqld(do_command(THD*)+0x47d) [0x36bda37]
/home/wqldb_8018/bin/mysqld(threadpool_process_request(THD*, int*)+0x19e) [0x3856e61]
/home/wqldb_8018/bin/mysqld() [0x38ad285]
/home/wqldb_8018/bin/mysqld() [0x38ad41b]
/home/wqldb_8018/bin/mysqld() [0x540999e]
/usr/lib64/libpthread.so.0(+0x7e25) [0x7fb49c0cae25]
/usr/lib64/libc.so.6(clone+0x6d) [0x7fb49a2e134d]

2. When the server is compiled as release, the client returns a error message:

ERROR 2027 (HY000) at line 1: Malformed packet

3. The two expressions are both caused by the failure of memory realloc in String class:
bool String::mem_realloc(size_t alloc_length, bool force_on_heap) {
...
    // Signal an error if len exceeds uint32 max on 64-bit word platform.
#if defined(__WORDSIZE) && (__WORDSIZE == 64)
    if (len > std::numeric_limits<uint32>::max()) return true;
#endif
...
}
Please notice that no error message is pushed on the error stack when len exceeds uint32 max.

Go on the process of failure:
bool Sql_cmd_dml::execute(THD *thd) {
...
  // Perform statement-specific execution
  res = execute_inner(thd); // res = true here
...
  if (res) goto err; 
...
err:
  DBUG_ASSERT(thd->is_error() || thd->killed); // debug builds failed here, no error in error stack, thd->is_error() = false
..
  return thd->is_error(); // return false but in fact there is error and no record is send
}

Then, since Sql_cmd_dml::execute returns true, the server sends the OK packet and the client receives it but parses it as a data packet and fails as "ERROR 2027 (HY000) at line 1: Malformed packet".

In conclusion, error message should push to error stack in String::mem_realloc.

How to repeat:
As above.
[4 Feb 2021 14:44] MySQL Verification Team
Hi Mr. Wei,

Thank you for your bug report.

However, this is not a bug.

The maximum, hard set size of the row is 4 Gb and you have hit it.

Try using prepared statements with chunks.

Not a bug.
[7 Feb 2021 3:37] Satya Bodapati
But you could throw a better error message "The row exceeded the max allowed packet size: 4GB" instead of "malformed packet" ?