From 0d8dce039bce76d83702ab5b773ca67120a042e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 26 May 2005 20:36:14 +0200 Subject: [PATCH 1/3] Fixed BUG#9937: Crash on call to stored procedure. This only showed up on two known platforms, both ia64 (one HP-UX and one Linux wich icc). For some reason, they only get half the stack size they are supposed to have, which makes deep SP recursion overrun the stack before check_stack_overrun() is triggered. Also made som minor fixes in the check_stack_overrun() definition, supporting variable margins. No test case added, but the reason for the bug report was a failed existing test case on these machines, which now works. sql/item_cmpfunc.cc: Adopted call to new check_stack_overrun() definition. sql/item_func.cc: Adopted calls to new check_stack_overrun() definition. sql/item_subselect.cc: Adopted call to new check_stack_overrun() definition. sql/mysql_priv.h: Changed definition of check_stack_overrun(), thread_stack_min variable no longer needed. sql/mysqld.cc: thread_stack_min variable no longer needed (with variable margin arg. to check_thread_overrun()). On (at least some) ia64 machines, it seems we only get half the requested stack in reality, so deep SP recursion crashes before the thread overrun check is triggered. We work around this by requesting twice the stack requested to get expected size. sql/sp_head.cc: Adopted call to new check_stack_overrun() definition, and use a wider margin execution. sql/sql_parse.cc: Modified check_stack_overrun() definition. Removed unused arg that didn't sever any purpose, and added a 'margin' argument to support different margins for different callrers. sql/table.cc: Adopted call to new check_stack_overrun() definition. --- sql/item_cmpfunc.cc | 2 +- sql/item_func.cc | 10 ++-------- sql/item_subselect.cc | 2 +- sql/mysql_priv.h | 4 ++-- sql/mysqld.cc | 24 +++++++++++++++++++++--- sql/sp_head.cc | 6 ++---- sql/sql_parse.cc | 4 ++-- sql/table.cc | 2 +- 8 files changed, 32 insertions(+), 22 deletions(-) diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 89897a9d74f..078fcb14ca3 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -2321,7 +2321,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) */ and_tables_cache= ~(table_map) 0; - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; // Fatal error flag is set! /* The following optimization reduces the depth of an AND-OR tree. diff --git a/sql/item_func.cc b/sql/item_func.cc index db2aa735b0e..68f1cc52cff 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -293,14 +293,11 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { DBUG_ASSERT(fixed == 0); Item **arg,**arg_end; -#ifndef EMBEDDED_LIBRARY // Avoid compiler warning - char buff[STACK_BUFF_ALLOC]; // Max argument in function -#endif used_tables_cache= not_null_tables_cache= 0; const_item_cache=1; - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) return TRUE; // Fatal error if flag is set! if (arg_count) { // Print purify happy @@ -2567,12 +2564,9 @@ bool udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { -#ifndef EMBEDDED_LIBRARY // Avoid compiler warning - char buff[STACK_BUFF_ALLOC]; // Max argument in function -#endif DBUG_ENTER("Item_udf_func::fix_fields"); - if (check_stack_overrun(thd, buff)) + if (check_stack_overrun(thd, STACK_MIN_SIZE+STACK_BUFF_ALLOC)) DBUG_RETURN(TRUE); // Fatal error flag is set! udf_func *tmp_udf=find_udf(u_d->name.str,(uint) u_d->name.length,1); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 0fbcf32a83c..55eb44c3c55 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -138,7 +138,7 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) DBUG_ASSERT(fixed == 0); engine->set_thd((thd= thd_param)); - if (check_stack_overrun(thd, (gptr)&res)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; res= engine->prepare(); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 5d11a047a8f..71c41547fe7 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1078,7 +1078,7 @@ extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout, slave_trans_retries; extern uint max_user_connections; extern ulong what_to_log,flush_time; -extern ulong query_buff_size, thread_stack,thread_stack_min; +extern ulong query_buff_size, thread_stack; extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit; extern ulong max_binlog_size, max_relay_log_size; extern ulong rpl_recovery_rank, thread_cache_size; @@ -1430,7 +1430,7 @@ inline int hexchar_to_int(char c) #ifndef EMBEDDED_LIBRARY extern "C" void unireg_abort(int exit_code); void kill_delayed_threads(void); -bool check_stack_overrun(THD *thd,char *dummy); +bool check_stack_overrun(THD *thd, long margin); #else #define unireg_abort(exit_code) DBUG_RETURN(exit_code) inline void kill_delayed_threads(void) {} diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8c5ce22f7a6..ef8a80a1d1c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -348,7 +348,7 @@ uint tc_heuristic_recover= 0; uint volatile thread_count, thread_running; ulong back_log, connect_timeout, concurrency; ulong server_id, thd_startup_options; -ulong table_cache_size, thread_stack, thread_stack_min, what_to_log; +ulong table_cache_size, thread_stack, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; ulong slave_net_timeout, slave_trans_retries; @@ -2090,7 +2090,13 @@ static void start_signal_handler(void) (void) pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_attr_setprio(&thr_attr,INTERRUPT_PRIOR); +#if defined(__ia64__) || defined(__ia64) + /* Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here */ + pthread_attr_setstacksize(&thr_attr,thread_stack*2); +#else pthread_attr_setstacksize(&thr_attr,thread_stack); +#endif #endif (void) pthread_mutex_lock(&LOCK_thread_count); @@ -3011,23 +3017,35 @@ int main(int argc, char **argv) init_signals(); if (!(opt_specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),CONNECT_PRIOR); +#if defined(__ia64__) || defined(__ia64) + /* Peculiar things with ia64 platforms - it seems we only have half the + stack size in reality, so we have to double it here */ + pthread_attr_setstacksize(&connection_attrib,thread_stack*2); +#else pthread_attr_setstacksize(&connection_attrib,thread_stack); +#endif #ifdef HAVE_PTHREAD_ATTR_GETSTACKSIZE { /* Retrieve used stack size; Needed for checking stack overflows */ size_t stack_size= 0; pthread_attr_getstacksize(&connection_attrib, &stack_size); +#if defined(__ia64__) || defined(__ia64) + stack_size/= 2; +#endif /* We must check if stack_size = 0 as Solaris 2.9 can return 0 here */ if (stack_size && stack_size < thread_stack) { if (global_system_variables.log_warnings) sql_print_warning("Asked for %ld thread stack, but got %ld", - thread_stack, stack_size); + thread_stack, stack_size); +#if defined(__ia64__) || defined(__ia64) + thread_stack= stack_size*2; +#else thread_stack= stack_size; +#endif } } #endif - thread_stack_min=thread_stack - STACK_MIN_SIZE; (void) thr_setconcurrency(concurrency); // 10 by default diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 988345694b2..f9aeb1e1f20 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -564,13 +564,11 @@ sp_head::execute(THD *thd) Item_change_list old_change_list; String old_packet; - -#ifndef EMBEDDED_LIBRARY - if (check_stack_overrun(thd, olddb)) + /* Use some extra margin for possible SP recursion and functions */ + if (check_stack_overrun(thd, 4*STACK_MIN_SIZE)) { DBUG_RETURN(-1); } -#endif dbchanged= FALSE; if (m_db.length && diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 7078c8e7181..298ecc06d20 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4985,11 +4985,11 @@ long max_stack_used; #endif #ifndef EMBEDDED_LIBRARY -bool check_stack_overrun(THD *thd,char *buf __attribute__((unused))) +bool check_stack_overrun(THD *thd, long margin) { long stack_used; if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >= - (long) thread_stack_min) + thread_stack - margin) { sprintf(errbuff[0],ER(ER_STACK_OVERRUN),stack_used,thread_stack); my_message(ER_STACK_OVERRUN,errbuff[0],MYF(0)); diff --git a/sql/table.cc b/sql/table.cc index db753b2ed1c..bc31a38f24a 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -1815,7 +1815,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds, bool res= FALSE; DBUG_ENTER("st_table_list::setup_ancestor"); - if (check_stack_overrun(thd, (char *)&res)) + if (check_stack_overrun(thd, STACK_MIN_SIZE)) return TRUE; for (tbl= ancestor; tbl; tbl= tbl->next_local) From d5f4c14b6e1ba0c0639e513d50eace20d6f8c15d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2005 14:48:33 +0200 Subject: [PATCH 2/3] Fixed BUG#9559: Functions: Numeric Operations using -ve value gives incorrect results. Actually a problem when converting decimal to int for user variables. mysql-test/r/sp.result: New test case for BUG#9559. mysql-test/t/sp.test: New test case for BUG#9559. sql/item_func.cc: Don't set the unsigned flag when converting decimal user var to int. --- mysql-test/r/sp.result | 11 +++++++++++ mysql-test/t/sp.test | 19 +++++++++++++++++++ sql/item_func.cc | 2 +- 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index c1164380f09..da54c100178 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -3098,4 +3098,15 @@ call bug5963_2(1)| call bug5963_2(1)| drop procedure bug5963_2| drop table t3| +drop function if exists bug9559| +create function bug9559() +returns int +begin +set @y = -6/2; +return @y; +end| +select bug9559()| +bug9559() +-3 +drop function bug9559| drop table t1,t2; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 80acaacfdb3..18389f4d80a 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -3801,6 +3801,25 @@ call bug5963_2(1)| drop procedure bug5963_2| drop table t3| +# +# BUG#9559: Functions: Numeric Operations using -ve value gives incorrect +# results. +# +--disable_warnings +drop function if exists bug9559| +--enable_warnings +create function bug9559() + returns int +begin + set @y = -6/2; + return @y; +end| + +select bug9559()| + +drop function bug9559| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item_func.cc b/sql/item_func.cc index 68f1cc52cff..92371e1a082 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3597,7 +3597,7 @@ longlong user_var_entry::val_int(my_bool *null_value) case DECIMAL_RESULT: { longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 1, &result); + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result); return result; } case STRING_RESULT: From 166accffda5d2019804c842a91b33e7d1a65f6ac Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 May 2005 16:19:25 +0200 Subject: [PATCH 3/3] Fixed BUG#8409: Stored procedure crash if function contains FLUSH by simply disabling FLUSH for stored functions. (I can't really work.) mysql-test/r/sp-error.result: New test case for BUG#8409. mysql-test/t/sp-error.test: New test case for BUG#8409. sql/sql_yacc.yy: Disable FLUSH for stored functions. --- mysql-test/r/sp-error.result | 8 ++++++++ mysql-test/t/sp-error.test | 15 +++++++++++++++ sql/sql_yacc.yy | 5 +++++ 3 files changed, 28 insertions(+) diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 7c19f60471a..5eb651e2fca 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -646,4 +646,12 @@ drop procedure if exists bug10537| create procedure bug10537() load data local infile '/tmp/somefile' into table t1| ERROR 0A000: LOAD DATA is not allowed in stored procedures +drop function if exists bug8409| +create function bug8409() +returns int +begin +flush tables; +return 5; +end| +ERROR 0A000: FLUSH is not allowed in stored procedures drop table t1| diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 67e9be5dd5d..78a6cdd49e1 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -905,6 +905,21 @@ create procedure bug10537() load data local infile '/tmp/somefile' into table t1| +# +# BUG#8409: Stored procedure crash if function contains FLUSH +# +--disable_warnings +drop function if exists bug8409| +--enable_warnings +--error ER_SP_BADSTATEMENT +create function bug8409() + returns int +begin + flush tables; + return 5; +end| + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6b9676c8124..feb9b9a6363 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6511,6 +6511,11 @@ flush: FLUSH_SYM opt_no_write_to_binlog { LEX *lex=Lex; + if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_FUNCTION) + { + my_error(ER_SP_BADSTATEMENT, MYF(0), "FLUSH"); + YYABORT; + } lex->sql_command= SQLCOM_FLUSH; lex->type=0; lex->no_write_to_binlog= $2; }