Bug #86711 OS X: Assertion failed: (table_share->tmp_table != ... adding new SQL statement
Submitted: 15 Jun 2017 9:36 Modified: 27 Jun 2017 14:22
Reporter: Debarun Banerjee Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Compiling Severity:S3 (Non-critical)
Version:8.0.3 OS:Any
Assigned to: CPU Architecture:Any

[15 Jun 2017 9:36] Debarun Banerjee
Description:
Following assert is hit on OS X after modifying some code structures to add a new SQL statement.

Assertion failed: (table_share->tmp_table != NO_TMP_TABLE || m_lock_type != 2), function ha_rnd_init, file
/home/debanerj/mysql-src1/sql/handler.cc, line 3055.

The issue is directly not related to the newly added code and is triggered by SELECT_LEX::is_empty_query() returning true while SELECT_LEX::m_empty_query is FALSE. This is confirmed by debugger and also using print.

My preliminary analysis shows this is an issue with compilation/linking. The reason seems to be that linker has merged ::m_empty_query with another function THD::release_resources_done.

1. bool is_empty_query() const { return m_empty_query; }  /* In class SELECT_LEX */
2. bool release_resources_done() const { return m_release_resources_done; } /* In class THD */

It results in is_empty_query() returning wrong result as the offsets of two variables within there respective class object are different. The assembly code from *.cc.o file also indicates that.

mysqld`THD::release_resources_done:
  mysqld[0x1004c06cc] <+12>: movb   0x23d9(%rdi), %al

dis -n SELECT_LEX::is_empty_query (sql_update.cc.o)
  sql_update.cc.o[0x7eec] <+12>: movb   0x2da(%rdi), %al

More details in section "How To Repeat".

How to repeat:
leo18.no.oracle.com
-----------------------------------------------
mysql-trunk
------------------------------------------------
commit 947ecbd9a9155ee7c0f04cea6c9239bb9d60798e
Author: Arnab Ray <arnab.r.ray@oracle.com>
Date:   Mon Jun 12 15:47:52 2017 +0530

1. Add a dummy variable to THD
==============================
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 966808c..25a30fe 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -977,6 +977,8 @@ public:
   struct  rand_struct rand;            // used for authentication
   struct  System_variables variables;  // Changeable local variables
   struct  System_status_var status_var; // Per thread statistic vars
+  ulong   dummy_var;
+
   struct  System_status_var *initial_status_var; /* used by show status */
   // has status_var already been added to global_status_var?
   bool status_var_aggregated;

2. Build debug binary
=====================
cd <build directory>
cmake -DWITH_DEBUG=1 -DWITH_BOOST=/usr/global/share <source directory>
make

3. Run the mtr test
===================
cd mysql-test

./mtr audit_log.audit_log_filter_field

mysql-test-run: *** ERROR: Error executing mysqld --initialize
see /export/home/tmp/debanerj/mysql-src1/bld_dbg/mysql-test/var/log/bootstrap.log for errors

bootstrap.log
-------------
Assertion failed: (table_share->tmp_table != NO_TMP_TABLE || m_lock_type != 2), function ha_rnd_init, file
/home/debanerj/mysql-src1/sql/handler.cc, line 3055.

The issue is triggered by SELECT_LEX::is_empty_query() returning true while SELECT_LEX::m_empty_query is FALSE.
bool is_empty_query() const { return m_empty_query; }  /* In class SELECT_LEX */

4. Check assembly code for SELECT_LEX::is_empty_query()
========================================================
A. From mysqld executable

lldb ./sql/mysqld
(lldb) dis -n SELECT_LEX::is_empty_query
mysqld`THD::release_resources_done:
mysqld[0x1004c06c0] <+0>:  pushq  %rbp
mysqld[0x1004c06c1] <+1>:  movq   %rsp, %rbp
mysqld[0x1004c06c4] <+4>:  movq   %rdi, -0x8(%rbp)
mysqld[0x1004c06c8] <+8>:  movq   -0x8(%rbp), %rdi
mysqld[0x1004c06cc] <+12>: movb   0x23d9(%rdi), %al
mysqld[0x1004c06d2] <+18>: andb   $0x1, %al
mysqld[0x1004c06d4] <+20>: movzbl %al, %sax
mysqld[0x1004c06d7] <+23>: popq   %rbp
mysqld[0x1004c06d8] <+24>: retq
mysqld[0x1004c06d9] <+25>: nopl   (%rax)

**It is merged with the assembly code for THD::release_resources_done. Now look at the compiler generated code for the two functions

B. SELECT_LEX::is_empty_query() from compiler generated object file

lldb ./sql/CMakeFiles/sql_main.dir/sql_update.cc.o
(lldb) dis -n SELECT_LEX::is_empty_query
sql_update.cc.o`SELECT_LEX::is_empty_query:
sql_update.cc.o[0x7ee0] <+0>:  pushq  %rbp
sql_update.cc.o[0x7ee1] <+1>:  movq   %rsp, %rbp
sql_update.cc.o[0x7ee4] <+4>:  movq   %rdi, -0x8(%rbp)
sql_update.cc.o[0x7ee8] <+8>:  movq   -0x8(%rbp), %rdi
sql_update.cc.o[0x7eec] <+12>: movb   0x2da(%rdi), %al
sql_update.cc.o[0x7ef2] <+18>: andb   $0x1, %al
sql_update.cc.o[0x7ef4] <+20>: movzbl %al, %eax
sql_update.cc.o[0x7ef7] <+23>: popq   %rbp
sql_update.cc.o[0x7ef8] <+24>: retq

C. THD::release_resources_done from compiler generated object file

lldb ./sql/CMakeFiles/sql_main.dir/mysqld_thd_manager.cc.o
(lldb) dis -n THD::release_resources_done
mysqld_thd_manager.cc.o`THD::release_resources_done:
mysqld_thd_manager.cc.o[0x16b0] <+0>:  pushq  %rbp
mysqld_thd_manager.cc.o[0x16b1] <+1>:  movq   %rsp, %rbp
mysqld_thd_manager.cc.o[0x16b4] <+4>:  movq   %rdi, -0x8(%rbp)
mysqld_thd_manager.cc.o[0x16b8] <+8>:  movq   -0x8(%rbp), %rdi
mysqld_thd_manager.cc.o[0x16bc] <+12>: movb   0x23d9(%rdi), %al
mysqld_thd_manager.cc.o[0x16c2] <+18>: andb   $0x1, %al
mysqld_thd_manager.cc.o[0x16c4] <+20>: movzbl %al, %eax
mysqld_thd_manager.cc.o[0x16c7] <+23>: popq   %rbp
mysqld_thd_manager.cc.o[0x16c8] <+24>: retq

The assembly code for the two functions are similar except 

sql_update.cc.o        [0x7eec] <+12>: movb   0x2da(%rdi), %al
mysqld_thd_manager.cc.o[0x16bc] <+12>: movb   0x23d9(%rdi), %al

SELECT_LEX::is_empty_query() is supposed to get the value of m_empty_query member which resides at offset 0x2da within the class object. Since linker looks to have wrongly merged it with THD::release_resources_done it is now returning from offset 0x23d9 which is incorrect.

Suggested fix:
I am not sure if this is because of installation issue like incompatible compiler and linker or if it is any linker bug or some other issue altogether. The issue could be related ICF [Identical Code Folding] linker optimization.

I observed following compiler version is getting used.
-- The C compiler identification is AppleClang 8.0.0.8000042
-- The CXX compiler identification is AppleClang 8.0.0.8000042
[19 Jun 2017 7:43] Terje Røsten
Posted by developer:
 
Please add cmake check for clang >= 8.0.0.8000042 on macOS.
[27 Jun 2017 14:22] Paul Dubois
Posted by developer:
 
Fixed in 8.0.3.

MySQL compilation on macOS using Clang now requires a Clang version
different from 8.0, which has problems with certain inline
constructs.
[11 Jul 2017 11:28] Erlend Dahl
Bug#86571 RPL FILTERS WARNINGS & ASSERTS (get_state() >= 0), (m_type == PFS_CLASS_RWLOCK)

was marked as a duplicate.