Commit 0d8dce03 authored by unknown's avatar unknown

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.
parent d4be3ae2
......@@ -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.
......
......@@ -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);
......
......@@ -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();
......
......@@ -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) {}
......
......@@ -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
......
......@@ -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 &&
......
......@@ -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));
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment