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