Bug #45620 Server process restart after calling functions from ha_innodb
Submitted: 19 Jun 2009 15:53 Modified: 24 Jun 2009 6:33
Reporter: Jens Muecke Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: User-defined functions ( UDF ) Severity:S3 (Non-critical)
Version:5.1, 5.4.0-beta OS:Linux
Assigned to: CPU Architecture:Any
Tags: function ha_innodb
Triage: Triaged: D1 (Critical)

[19 Jun 2009 15:53] Jens Muecke
Description:
In the plugins-directory is a shared library named ha_innodb.so This library can be loaded in sql by the following command:

"CREATE FUNCTION sync RETURNS INTEGER SONAME 'ha_innodb';"

There are 4 functions you can load from ha_innodb:

mysql> select * from func;
+----------+-----+--------------+----------+
| name     | ret | dl           | type     |
+----------+-----+--------------+----------+
| buf_pool |   2 | ha_innodb.so | function | 
| sync     |   2 | ha_innodb.so | function | 
| recv_sys |   2 | ha_innodb.so | function | 
| os_aio   |   2 | ha_innodb.so | function | 
+----------+-----+--------------+----------+

Calling any of these functions crash the server process.

select buf_pool();

strace output:
fcntl(4, F_SETFL, O_RDWR|O_NONBLOCK)    = 0
accept(4, {sa_family=AF_FILE, path="<g\377\177"...}, [7438867345033920514]) = 21
fcntl(4, F_SETFL, O_RDWR)               = 0
getsockname(21, {sa_family=AF_FILE, path="/home/jens/db/\1"...}, [7438867345033920550]) = 0
fcntl(21, F_SETFL, O_RDONLY)            = 0
fcntl(21, F_GETFL)                      = 0x2 (flags O_RDWR)
fcntl(21, F_SETFL, O_RDWR|O_NONBLOCK)   = 0
setsockopt(21, SOL_IP, IP_TOS, [8], 4)  = -1 EOPNOTSUPP (Operation not supported)
mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|0x20000, -1, 0) = 0x7f185f37c000
mprotect(0x7f185f37c000, 4096, PROT_NONE) = 0
clone(child_stack=0x7f185f39c230, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f185f39c9e0, tls=0x7f185f39c950, child_tidptr=0x7f185f39c9e0) = 29981
futex(0xb16fc0, FUTEX_WAKE_PRIVATE, 1)  = 1
select(5, [3 4], NULL, NULL, NULLupeek: ptrace(PTRACE_PEEKUSER,29976,120,0): No such process

How to repeat:
Calling the function again.

Suggested fix:
More checks when creating this functions.
[20 Jun 2009 6:51] Sveta Smirnova
Thank you for the report.

Verified as described.

Backtrace from my env:

/users/ssmirnova/mysql-5.4.0-beta-b/lib/mysql/plugin/ha_innodb.so(sync_array_create+0x103) [0xa3427b]
/users/ssmirnova/mysql-5.4.0-beta-b/lib/mysql/plugin/ha_innodb.so(sync_init+0x2d) [0xa360c9]
./libexec/mysqld(udf_handler::fix_fields(THD*, Item_result_field*, unsigned int, Item**)+0x375) [0x8123de1]
./libexec/mysqld(Item_udf_func::fix_fields(THD*, Item**)+0x1d) [0x812b325]
./libexec/mysqld(setup_fields(THD*, Item**, List<Item>&, enum_mark_columns, List<Item>*, bool)+0x150) [0x81e656c]
./libexec/mysqld(JOIN::prepare(Item***, TABLE_LIST*, unsigned int, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, st_select_lex*, st_select_lex_unit*)+0x5b0) [0x82026e4]
./libexec/mysqld(mysql_select(THD*, Item***, TABLE_LIST*, unsigned int, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*)+0x4ef) [0x8219293]
./libexec/mysqld(handle_select(THD*, st_lex*, select_result*, unsigned long)+0x107) [0x821978b]
./libexec/mysqld [0x81a4221]
./libexec/mysqld(mysql_execute_command(THD*)+0xf90) [0x81a81cc]
./libexec/mysqld(mysql_parse(THD*, char const*, unsigned int, char const**)+0x1dd) [0x81af871]
./libexec/mysqld(dispatch_command(enum_server_command, THD*, char*, unsigned int)+0x420) [0x81afcb4]
./libexec/mysqld(do_command(THD*)+0xcb) [0x81b0cbb]
./libexec/mysqld(handle_one_connection+0x597) [0x81a164f]
/lib/libpthread.so.0 [0x45fbd4]
/lib/libc.so.6(__clone+0x5e) [0x3b74fe]
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort...
thd->query at 0x9fc8e30 = select sync()

mysql output:

mysql> select * from mysql.func;
+------+-----+--------------+----------+
| name | ret | dl           | type     |
+------+-----+--------------+----------+
| sync |   2 | ha_innodb.so | function | 
+------+-----+--------------+----------+
1 row in set (0.02 sec)

mysql> select sync();
ERROR 2013 (HY000): Lost connection to MySQL server during query
[23 Jun 2009 13:51] Trudy Pelzer
Sveta: Please verify whether this is specific to 5.4.0
or whether it also happens in 5.1. Thanks.
[24 Jun 2009 6:33] Sveta Smirnova
Same problem occurs in version 5.1 as well
[26 Jun 2009 17:48] Sergei Golubchik
Not a big deal.
One should not grant INSERT privilege on mysql.func to untrusted users.
UDF interface isn't very fool-proof, even perfectly valid UDF can crash the server if loaded incorrectly.
[27 Jun 2009 4:12] James Day
Jens, to prevent this you can move the InnoDB plugin if you don't need to use it. If you do need InnoDB then using the built in version is possible.
[27 Jun 2009 5:50] Sergei Golubchik
As a workaround, one can build InnoDB with -fvisibility=hidden (which is a generally recommended anyways - http://gcc.gnu.org/wiki/Visibility).

But to support this we need to specify visibility explicitly in plugin.h.
Like this:

=== modified file 'include/mysql/plugin.h'
--- include/mysql/plugin.h      2009-05-14 08:56:34 +0000
+++ include/mysql/plugin.h      2009-06-27 05:48:58 +0000
@@ -19,9 +19,14 @@
 /*
   On Windows, exports from DLL need to be declared
 */
-#if (defined(_WIN32) && defined(MYSQL_DYNAMIC_PLUGIN))
+#ifdef MYSQL_DYNAMIC_PLUGIN
+#ifdef _WIN32
 #define MYSQL_PLUGIN_EXPORT extern "C" __declspec(dllexport)
-#else
+#elif __GNUC__ >= 4
+#define MYSQL_PLUGIN_EXPORT extern "C" __attribute__ ((visibility("default")))
+#endif
+#endif
+#ifndef MYSQL_PLUGIN_EXPORT
 #define MYSQL_PLUGIN_EXPORT
 #endif