Description:
Developers who are building a new component that uses mysql_command_xxx services (mysql_command_factory, mysql_command_query, etc.) cannot reuse the same connection to run multiple queries (tested with 'SELECT's but may also be true for 'INSERT' / 'UPDATE' / 'DELETE').
Basically, the following sequence of calls will crash the server
cmd_factory_srv->init(&mysql_h);
cmd_factory_srv->connect(mysql_h);
cmd_query_srv->query(mysql_h, "SELECT 1");
cmd_query_srv->query(mysql_h, "SELECT 1");
5 mysqld-debug 0x0000000112ba9d98 Callback_command_delegate::field_metadata(st_send_field*, CHARSET_INFO const*) + 232
6 mysqld-debug 0x0000000112bab241 Command_delegate::call_field_metadata(void*, st_send_field*, CHARSET_INFO const*) + 97
7 mysqld-debug 0x000000011083fffc Protocol_callback::send_field_metadata(Send_field*, CHARSET_INFO const*) + 172
8 mysqld-debug 0x0000000110410149 THD::send_result_metadata(mem_root_deque<Item*> const&, unsigned int) + 713
9 mysqld-debug 0x00000001102b7f1f Query_result_send::send_result_set_metadata(THD*, mem_root_deque<Item*> const&, unsigned int) + 47
10 mysqld-debug 0x00000001106c17d6 Query_expression::ExecuteIteratorQuery(THD*) + 806
11 mysqld-debug 0x00000001106c2294 Query_expression::execute(THD*) + 324
12 mysqld-debug 0x00000001105dcc40 Sql_cmd_dml::execute_inner(THD*) + 224
13 mysqld-debug 0x00000001105dbba6 Sql_cmd_dml::execute(THD*) + 2470
14 mysqld-debug 0x000000011052d0b0 mysql_execute_command(THD*, bool) + 30640
15 mysqld-debug 0x00000001105235d0 dispatch_sql_command(THD*, Parser_state*) + 2784
16 mysqld-debug 0x000000011051eb3d dispatch_command(THD*, COM_DATA const*, enum_server_command) + 9005
17 mysqld-debug 0x000000011084b062 Srv_session::execute_command(enum_server_command, COM_DATA const*, CHARSET_INFO const*, st_command_service_cbs const*, cs_text_or_binary, void*) + 1362
18 mysqld-debug 0x000000011080eb9f command_service_run_command(Srv_session*, enum_server_command, COM_DATA const*, CHARSET_INFO const*, st_command_service_cbs const*, cs_text_or_binary, void*) + 111
19 mysqld-debug 0x0000000112baa545 cs::csi_advanced_command(MYSQL*, enum_server_command, unsigned char const*, unsigned long, unsigned char const*, unsigned long, bool, MYSQL_STMT*) + 709
20 mysqld-debug 0x00000001107ba3f5 mysql_send_query + 773
21 mysqld-debug 0x00000001107bb1da mysql_real_query + 378
22 mysqld-debug 0x0000000112ba6f07 mysql_command_services_imp::query(MYSQL_H_imp*, char const*, unsigned long) + 71
23 component_test_mysql_command_servic 0x000000011ba6f0dd test_mysql_command_services_udf(UDF_INIT*, UDF_ARGS*, char*, unsigned long*, unsigned char*, unsigned char*) + 813
24 mysqld-debug 0x000000010fee9e13 udf_handler::val_str(String*, String*) + 499
25 mysqld-debug 0x000000010feead87 Item_func_udf_str::val_str(String*) + 119
26 mysqld-debug 0x000000010fe29b9b Item::send(Protocol*, String*) + 107
27 mysqld-debug 0x00000001104104b8 THD::send_result_set_row(mem_root_deque<Item*> const&) + 360
28 mysqld-debug 0x00000001102b802f Query_result_send::send_data(THD*, mem_root_deque<Item*> const&) + 95
29 mysqld-debug 0x00000001106c1e42 Query_expression::ExecuteIteratorQuery(THD*) + 2450
30 mysqld-debug 0x00000001106c2294 Query_expression::execute(THD*) + 324
31 mysqld-debug 0x00000001105dcc40 Sql_cmd_dml::execute_inner(THD*) + 224
32 mysqld-debug 0x00000001105dbba6 Sql_cmd_dml::execute(THD*) + 2470
33 mysqld-debug 0x000000011052d0b0 mysql_execute_command(THD*, bool) + 30640
34 mysqld-debug 0x00000001105235d0 dispatch_sql_command(THD*, Parser_state*) + 2784
35 mysqld-debug 0x000000011051eb3d dispatch_command(THD*, COM_DATA const*, enum_server_command) + 9005
36 mysqld-debug 0x0000000110521ba7 do_command(THD*) + 2087
37 mysqld-debug 0x0000000110810264 handle_connection(void*) + 500
38 mysqld-debug 0x0000000112a432a4 pfs_spawn_thread(void*) + 324
39 libsystem_pthread.dylib 0x00007ff809557253 _pthread_start + 99
40 libsystem_pthread.dylib 0x00007ff809552bef thread_start + 15
Most probably the issue was introduced by this commit
https://github.com/mysql/mysql-server/commit/5dc1a146fc5e61e35fd7861f3cf2fc28f3d655da
(in the 'csi_advanced_command()' part). Although it fixes the memory leak, 'mcs_extn->consumer_srv_data' when is not nullptr cannot be simply re-used here as its 'mcs_extn->data' member has already been set to nullptr by 'std::exchange()' inside 'csi_read_rows()'.
How to repeat:
Apply the attached "steps_to_reproduce.diff" patch. It modifies the "test_mysql_command_services" test component so that its "test_mysql_command_services_udf" UDF now takes one more parameter - the number of query executions.
It also extends the 'test_sevices.test_mysql_command_services_component' MTR test case with 2 more calls
SELECT test_mysql_command_services_udf("SELECT 1");
SELECT test_mysql_command_services_udf("SELECT 1", 2);
Suggested fix:
Instead of simply reusing 'mcs_extn->consumer_srv_data', call factory_srv->end() and 'factory_srv->start()' in case when this value is not nullptr.
See the attached "suggested_fix.diff" patch.