[MDEV-32495] Server crash on PS CALL execution, if SP has been changed after 1st execution Created: 2023-10-17  Updated: 2023-12-12

Status: Confirmed
Project: MariaDB Server
Component/s: Prepared Statements, Stored routines
Affects Version/s: 10.11.5
Fix Version/s: 10.4, 10.5, 10.6, 10.11, 11.0, 11.1

Type: Bug Priority: Critical
Reporter: Lawrin Novitsky Assignee: Dmitry Shulga
Resolution: Unresolved Votes: 0
Labels: crash


 Description   

If SP CALLhas been prepared and executed, and then the SP is changed(DROPped and CREATEd) by someone, the second execution of that CALL statement will reliably crash the server. The C API code to repeat

MYSQL      *ma;
  MYSQL_STMT *stmt;
  MYSQL_BIND bind[3], paramBind[3];
  MARIADB_CHARSET_INFO *cs;
  my_bool    is_null= 0, error= 0;
  unsigned int i= 0, j= 0, res[3]={30,20,50}, param[3]= {30,20,50};
 
  ma = mysql_init(NULL);
  mysql_optionsv(ma, MYSQL_SET_CHARSET_NAME, "latin1");
 
  if (!mysql_real_connect(ma, "localhost", "root", "root", "test", 3306, NULL, CLIENT_MULTI_RESULTS | CLIENT_MULTI_STATEMENTS))
  {
    printf("Could not connect: %s\n", mysql_error(ma));
    exit(1);
  }
  else
  {
    printf("Server info %s\nClient info: %s\n",
    mysql_get_server_info(ma), mysql_get_client_info());
  }
 
  stmt= mysql_stmt_init(ma);
 
  mysql_query(ma, "DROP PROCEDURE IF EXISTS t_outparams");
  mysql_query(ma, "CREATE PROCEDURE t_outparams("
              "  IN p_in INT, "
              "  OUT p_out INT, "
              "  INOUT p_inout INT) "
              "BEGIN "
              "  SET p_in = p_in*10, p_out = (p_in+p_inout)*10, p_inout = p_inout*10; "
              "END");
  mysql_stmt_prepare(stmt, "CALL t_outparams(?,?,?)", -1);
 
  memset(&bind, 0, sizeof(bind));
  memset(&bind, 0, sizeof(paramBind));
 
  bind[0].buffer_type=  MYSQL_TYPE_LONG;
  bind[0].buffer=       (void *)res;
  bind[0].buffer_length= sizeof(int);
  bind[0].is_null=      NULL;
  bind[0].error=        NULL;
 
  bind[1].buffer_type=  MYSQL_TYPE_LONG;
  bind[1].buffer=       (void *)(res + 1);
  bind[1].buffer_length= sizeof(int);
  bind[1].is_null=      NULL;
  bind[1].error=        NULL;
 
  bind[2].buffer_type=  MYSQL_TYPE_LONG;
  bind[2].buffer=       (void *)(res + 2);
  bind[2].buffer_length= sizeof(int);
  bind[2].is_null=      NULL;
  bind[2].error=        NULL;
 
  mysql_stmt_bind_param(stmt, bind);
  mysql_stmt_execute(stmt);
  mysql_stmt_store_result(stmt);
  mysql_stmt_bind_result(stmt, bind);
 
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
  {
    printf("-- Values= %d %d %d\n", res[0], res[1], res[2]);
  }
  printf("---------------------------------------------------\n");
  mysql_stmt_next_result(stmt);
  if (mysql_stmt_field_count(stmt) == 0)
  {
    printf("SP returned: %lld", mysql_stmt_affected_rows(stmt));
  }
 
  mysql_query(ma, "DROP PROCEDURE t_outparams");
 
  mysql_query(ma, "CREATE PROCEDURE t_outparams("
    "  OUT p_out VARCHAR(19), "
    "  IN p_in INT, "
    "  INOUT p_inout INT) "
    "BEGIN "
    "  SET p_in = 300, p_out := 'This is OUT param', p_inout = 200; "
    "  SELECT p_inout, p_in, substring(p_out, 9);"
    "END");
 
  mysql_stmt_bind_param(stmt, bind);
  mysql_stmt_execute(stmt);
  mysql_stmt_store_result(stmt);
  mysql_stmt_bind_result(stmt, bind);
 
  while (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA)
  {
    printf("-- Values= %d %d %d\n", res[0], res[1], res[2]);
  }
  printf("---------------------------------------------------\n");
  mysql_stmt_next_result(stmt);
  mysql_stmt_close(stmt);
  
  mysql_query(ma, "DROP PROCEDURE t_outparams");
  mysql_close(ma);

I don't have latest versions for all branches, but this crashes all supported server release series

Server info 10.11.5-MariaDB
Client info: 3.3.8
-- Values= 3500 500 50
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 10.5.20-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 10.6.11-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 10.4.31-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 10.10.2-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 10.9.4-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Could not connect: Can't connect to server on 'localhost' (10061)
Server info 11.0.2-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================
Server info 11.1.2-MariaDB
Client info: 3.3.8
-- Values= 20000 0 0
---------------------------------------------------
SP returned: 0
-- Values= 200 300 0
---------------------------------------------------
Call mysql_stmt_next_result unexpectedly returned !0 because of Lost connection to server during query (errno: 2013)
===================================================

Unlikely this matters, but I am testing on Windows. The backtrace from the log:

Server version: 10.11.5-MariaDB source revision: 7875294b6b74b53dd3aaa723e6cc103d2bb47b2c
key_buffer_size=134217728
read_buffer_size=131072
max_used_connections=1
max_threads=65537
thread_count=1
It is possible that mysqld could use up to 
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_threads = 142742958 K  bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
 
Thread pointer: 0x1a98daccf98
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...
server.dll!my_convert()[ctype.c:1267]
server.dll!String::copy()[sql_string.cc:476]
server.dll!Protocol::net_store_data_cs()[protocol.cc:104]
server.dll!Protocol_text::store_field_metadata()[protocol.cc:854]
server.dll!Protocol::send_result_set_metadata()[protocol.cc:1213]
server.dll!Protocol_binary::send_out_parameters()[protocol.cc:1965]
server.dll!Prepared_statement::execute()[sql_prepare.cc:5335]
server.dll!Prepared_statement::execute_loop()[sql_prepare.cc:4646]
server.dll!mysql_stmt_execute_common()[sql_prepare.cc:3578]
server.dll!mysqld_stmt_execute()[sql_prepare.cc:3352]
server.dll!dispatch_command()[sql_parse.cc:1826]
server.dll!do_command()[sql_parse.cc:1407]
server.dll!tp_callback()[threadpool_common.cc:245]
KERNEL32.DLL!TermsrvSetKeySecurity()
ntdll.dll!RtlEqualUnicodeString()
ntdll.dll!TpReleaseCleanupGroupMembers()
KERNEL32.DLL!BaseThreadInitThunk()
ntdll.dll!RtlUserThreadStart()
 
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort.
Query (0x1a98db75090): CALL t_outparams(?,?,?)
Connection ID (thread ID): 12
Status: NOT_KILLED
 
Optimizer switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on,not_null_range_scan=off,hash_join_cardinality=off

I did not dig much, but looks like the order of in/out parameters is what matters here - in original test the first change of procedure did not change that, but added a resultset, and it did not crash the server.

Not sure if it's critical - unlikely something that people do on production systems, but it's still a crash.



 Comments   
Comment by Lawrin Novitsky [ 2023-11-04 ]

Sorry, I've set 10.11 as affected version, but I believe that older branches are also affected, and it has to be fixed in all supported versions

Generated at Thu Feb 08 10:31:48 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.