Below is the list of changes that have just been committed into a local
5.0 repository of thek. When thek does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-10-22 11:57:43+02:00, thek@adventure.(none) +8 -0
Bug #31153 calling stored procedure crashes server if available memory is low
When the server was out of memory it crashed because of invalid memory access.
This patch detects the failed memory allocation and have the server output a
proper error message.
mysys/my_new.cc@stripped, 2007-10-22 11:57:41+02:00, thek@adventure.(none) +3 -3
Due to an inconsistency in gcc, the operator 'new' needs to be declared with an
empty throw() directive or it will not return a NULL pointer on a failed
malloc call.
sql/sp_head.cc@stripped, 2007-10-22 11:57:41+02:00, thek@adventure.(none) +46 -5
Added check for out-of-memory on a 'new' operation.
Refactored reset_lex method to return a error state code instead of void.
sql/sp_head.h@stripped, 2007-10-22 11:57:41+02:00, thek@adventure.(none) +3 -3
Due to an inconsistency in gcc, the operator 'new' needs to be declared with an
empty throw() directive or it will not return a NULL pointer on a failed
malloc call.
sql/sql_base.cc@stripped, 2007-10-22 11:57:41+02:00, thek@adventure.(none) +13 -0
Created new error handler for Out-Of-Memory errors. This is needed to avoid
new memory allocations attempt in my_message_sql call stack.
sql/sql_class.h@stripped, 2007-10-22 11:57:42+02:00, thek@adventure.(none) +25 -0
Created new error handler for Out-Of-Memory errors. This is needed to avoid
new memory allocations attempt in my_message_sql call stack.
sql/sql_lex.h@stripped, 2007-10-22 11:57:42+02:00, thek@adventure.(none) +6 -0
Overloaded new and delete operators for the sp_head class.
sql/sql_parse.cc@stripped, 2007-10-22 11:57:42+02:00, thek@adventure.(none) +6 -2
Removed assertion to be able to test fatal error recovery in debug mode.
Added code to restore the net object associated with the recycled thd object
so that it won't remember runtime settings from previous statements.
sql/sql_yacc.yy@stripped, 2007-10-22 11:57:42+02:00, thek@adventure.(none) +31 -11
If reset_lex fails, the parsing must stop to prevent access to uninitialized
objects. The same goes for any memory allocation attempt.
diff -Nrup a/mysys/my_new.cc b/mysys/my_new.cc
--- a/mysys/my_new.cc 2006-12-23 20:04:08 +01:00
+++ b/mysys/my_new.cc 2007-10-22 11:57:41 +02:00
@@ -22,17 +22,17 @@
#ifdef USE_MYSYS_NEW
-void *operator new (size_t sz)
+void *operator new (size_t sz) throw ()
{
return (void *) malloc (sz ? sz : 1);
}
-void *operator new[] (size_t sz)
+void *operator new[] (size_t sz) throw ()
{
return (void *) malloc (sz ? sz : 1);
}
-void operator delete (void *ptr)
+void operator delete (void *ptr) throw ()
{
if (ptr)
free(ptr);
diff -Nrup a/sql/sp_head.cc b/sql/sp_head.cc
--- a/sql/sp_head.cc 2007-07-31 14:23:23 +02:00
+++ b/sql/sp_head.cc 2007-10-22 11:57:41 +02:00
@@ -411,7 +411,7 @@ check_routine_name(LEX_STRING ident)
*/
void *
-sp_head::operator new(size_t size)
+sp_head::operator new(size_t size) throw()
{
DBUG_ENTER("sp_head::operator new");
MEM_ROOT own_root;
@@ -419,6 +419,13 @@ sp_head::operator new(size_t size)
init_alloc_root(&own_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
sp= (sp_head *) alloc_root(&own_root, size);
+ if (sp == NULL)
+ {
+ THD *thd= current_thd;
+ thd->fatal_error();
+ my_error(ER_OUTOFMEMORY, MYF(0));
+ return NULL;
+ }
sp->main_mem_root= own_root;
DBUG_PRINT("info", ("mem_root 0x%lx", (ulong) &sp->mem_root));
DBUG_RETURN(sp);
@@ -429,6 +436,10 @@ sp_head::operator delete(void *ptr, size
{
DBUG_ENTER("sp_head::operator delete");
MEM_ROOT own_root;
+
+ if (ptr == NULL)
+ DBUG_VOID_RETURN;
+
sp_head *sp= (sp_head *) ptr;
/* Make a copy of main_mem_root as free_root will free the sp */
@@ -472,6 +483,17 @@ sp_head::init(LEX *lex)
lex->spcont= m_pcont= new sp_pcontext();
+ if (!lex->spcont)
+ {
+ THD *thd= current_thd;
+ OOM_error_handler hndl;
+ thd->push_internal_handler(&hndl);
+ my_error(ER_OUTOFMEMORY,MYF(0));
+ thd->fatal_error();
+ thd->pop_internal_handler();
+ DBUG_VOID_RETURN;
+ }
+
/*
Altough trg_table_fields list is used only in triggers we init for all
types of stored procedures to simplify reset_lex()/restore_lex() code.
@@ -1795,16 +1817,35 @@ sp_head::execute_procedure(THD *thd, Lis
}
-// Reset lex during parsing, before we parse a sub statement.
-void
+/**
+ @brief Reset lex during parsing, before we parse a sub statement.
+
+ @param thd Thread handler.
+
+ @return Error state
+ @retval true An error occurred.
+ @retval false Success.
+*/
+
+bool
sp_head::reset_lex(THD *thd)
{
DBUG_ENTER("sp_head::reset_lex");
LEX *sublex;
LEX *oldlex= thd->lex;
+ sublex= new st_lex;
+ if (sublex == 0)
+ {
+ thd->push_internal_handler(new OOM_error_handler());
+ my_error(ER_OUTOFMEMORY, MYF(0));
+ thd->fatal_error();
+ thd->pop_internal_handler();
+ DBUG_RETURN(TRUE);
+ }
+
+ thd->lex= sublex;
(void)m_lex.push_front(oldlex);
- thd->lex= sublex= new st_lex;
/* Reset most stuff. */
lex_start(thd);
@@ -1827,7 +1868,7 @@ sp_head::reset_lex(THD *thd)
sublex->interval_list.empty();
sublex->type= 0;
- DBUG_VOID_RETURN;
+ DBUG_RETURN(FALSE);
}
// Restore lex during parsing, after we have parsed a sub statement.
diff -Nrup a/sql/sp_head.h b/sql/sp_head.h
--- a/sql/sp_head.h 2007-07-12 20:26:38 +02:00
+++ b/sql/sp_head.h 2007-10-22 11:57:41 +02:00
@@ -191,10 +191,10 @@ public:
Security_context m_security_ctx;
static void *
- operator new(size_t size);
+ operator new(size_t size) throw ();
static void
- operator delete(void *ptr, size_t size);
+ operator delete(void *ptr, size_t size) throw ();
sp_head();
@@ -254,7 +254,7 @@ public:
}
// Resets lex in 'thd' and keeps a copy of the old one.
- void
+ bool
reset_lex(THD *thd);
// Restores lex in 'thd' from our copy, but keeps some status from the
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc 2007-08-24 13:28:10 +02:00
+++ b/sql/sql_base.cc 2007-10-22 11:57:41 +02:00
@@ -81,6 +81,19 @@ bool Prelock_error_handler::safely_trapp
}
+bool OOM_error_handler::handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd)
+{
+ fprintf(stderr,"Fatal error: Out of memory (%d)\n",sql_errno);
+ return TRUE;
+}
+
+bool OOM_error_handler::safely_trapped_errors(void)
+{
+ return TRUE;
+}
+
TABLE *unused_tables; /* Used by mysql_test */
HASH open_cache; /* Used by mysql_test */
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h 2007-08-02 02:39:10 +02:00
+++ b/sql/sql_class.h 2007-10-22 11:57:42 +02:00
@@ -2431,6 +2431,31 @@ public:
void cleanup();
};
+
+/**
+ @brief Error handler for OOM errors.
+*/
+
+class OOM_error_handler : public Internal_error_handler
+{
+public:
+ OOM_error_handler()
+ : m_handled_errors(0), m_unhandled_errors(0)
+ {}
+
+ virtual ~OOM_error_handler() {}
+
+ virtual bool handle_error(uint sql_errno,
+ MYSQL_ERROR::enum_warning_level level,
+ THD *thd);
+
+ bool safely_trapped_errors();
+
+private:
+ int m_handled_errors;
+ int m_unhandled_errors;
+};
+
/* Functions in sql_class.cc */
void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
diff -Nrup a/sql/sql_lex.h b/sql/sql_lex.h
--- a/sql/sql_lex.h 2007-08-28 17:51:02 +02:00
+++ b/sql/sql_lex.h 2007-10-22 11:57:42 +02:00
@@ -1169,6 +1169,11 @@ typedef struct st_lex : public Query_tab
st_lex();
+ static void*
+ operator new(size_t sz) throw() { return (void *) malloc (sz ? sz : 1); }
+
+ void operator delete (void *ptr) throw() { free(ptr); }
+
virtual ~st_lex()
{
destroy_query_tables_list();
@@ -1303,3 +1308,4 @@ extern void lex_start(THD *thd);
extern void lex_end(LEX *lex);
extern int MYSQLlex(void *arg, void *yythd);
extern char *skip_rear_comments(CHARSET_INFO *cs, char *begin, char *end);
+
diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc
--- a/sql/sql_parse.cc 2007-09-03 09:22:54 +02:00
+++ b/sql/sql_parse.cc 2007-10-22 11:57:42 +02:00
@@ -34,6 +34,7 @@
#include "sp_cache.h"
#include "sql_trigger.h"
+
#ifdef HAVE_OPENSSL
/*
Without SSL the handshake consists of one packet. This packet
@@ -5850,6 +5851,7 @@ void mysql_reset_thd_for_next_command(TH
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->tmp_table_used= 0;
thd->thread_specific_used= FALSE;
+
if (!thd->in_sub_stmt)
{
if (opt_bin_log)
@@ -5862,6 +5864,10 @@ void mysql_reset_thd_for_next_command(TH
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
}
+
+
+ thd->net.no_send_error= FALSE;
+ thd->net.no_send_ok= FALSE;
DBUG_VOID_RETURN;
}
@@ -6098,10 +6104,8 @@ void mysql_parse(THD *thd, const char *i
}
else
{
- DBUG_ASSERT(thd->net.report_error);
DBUG_PRINT("info",("Command aborted. Fatal_error: %d",
thd->is_fatal_error));
-
query_cache_abort(&thd->net);
}
if (thd->lex->sphead)
diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy 2007-09-12 20:39:32 +02:00
+++ b/sql/sql_yacc.yy 2007-10-22 11:57:42 +02:00
@@ -1628,6 +1628,8 @@ create_function_tail:
}
/* Order is important here: new - reset - init */
sp= new sp_head();
+ if (sp == NULL)
+ MYSQL_YYABORT;
sp->reset_thd_mem_root(thd);
sp->init(lex);
sp->init_sp_name(thd, lex->spname);
@@ -1929,7 +1931,8 @@ sp_decl:
{
LEX *lex= Lex;
- lex->sphead->reset_lex(YYTHD);
+ if (lex->sphead->reset_lex(YYTHD))
+ MYSQL_YYABORT;
lex->spcont->declare_var_boundary($2);
}
type
@@ -1937,6 +1940,10 @@ sp_decl:
{
LEX *lex= Lex;
sp_pcontext *pctx= lex->spcont;
+ if (pctx == 0)
+ {
+ MYSQL_YYABORT;
+ }
uint num_vars= pctx->context_var_count();
enum enum_field_types var_type= (enum enum_field_types) $4;
Item *dflt_value_item= $5;
@@ -2064,7 +2071,8 @@ sp_decl:
sp_cursor_stmt:
{
- Lex->sphead->reset_lex(YYTHD);
+ if(Lex->sphead->reset_lex(YYTHD))
+ MYSQL_YYABORT;
/* We use statement here just be able to get a better
error message. Using 'select' works too, but will then
@@ -2230,7 +2238,8 @@ sp_proc_stmt:
LEX *lex= thd->lex;
Lex_input_stream *lip= thd->m_lip;
- lex->sphead->reset_lex(thd);
+ if (lex->sphead->reset_lex(thd))
+ MYSQL_YYABORT;
lex->sphead->m_tmp_query= lip->tok_start;
}
statement
@@ -2275,7 +2284,7 @@ sp_proc_stmt:
sp->restore_lex(thd);
}
| RETURN_SYM
- { Lex->sphead->reset_lex(YYTHD); }
+ { if(Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
expr
{
LEX *lex= Lex;
@@ -2472,7 +2481,7 @@ sp_fetch_list:
;
sp_if:
- { Lex->sphead->reset_lex(YYTHD); }
+ { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
expr THEN_SYM
{
LEX *lex= Lex;
@@ -2522,7 +2531,7 @@ simple_case_stmt:
{
LEX *lex= Lex;
case_stmt_action_case(lex);
- lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ if (lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
}
expr
{
@@ -2571,7 +2580,7 @@ searched_when_clause_list:
simple_when_clause:
WHEN_SYM
{
- Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
}
expr
{
@@ -2592,7 +2601,7 @@ simple_when_clause:
searched_when_clause:
WHEN_SYM
{
- Lex->sphead->reset_lex(YYTHD); /* For expr $3 */
+ if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; /* For expr $3 */
}
expr
{
@@ -2703,7 +2712,7 @@ sp_unlabeled_control:
lex->sphead->add_instr(i);
}
| WHILE_SYM
- { Lex->sphead->reset_lex(YYTHD); }
+ { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
expr DO_SYM
{
LEX *lex= Lex;
@@ -2729,7 +2738,7 @@ sp_unlabeled_control:
lex->sphead->do_cont_backpatch();
}
| REPEAT_SYM sp_proc_stmts1 UNTIL_SYM
- { Lex->sphead->reset_lex(YYTHD); }
+ { if (Lex->sphead->reset_lex(YYTHD)) MYSQL_YYABORT; }
expr END REPEAT_SYM
{
LEX *lex= Lex;
@@ -4271,6 +4280,8 @@ select_init2:
select_part2
{
LEX *lex= Lex;
+ if (lex == NULL)
+ MYSQL_YYABORT;
SELECT_LEX * sel= lex->current_select;
if (lex->current_select->set_braces(0))
{
@@ -8422,7 +8433,14 @@ option_type_value:
QQ: May be we should simply prohibit group assignments in SP?
*/
- Lex->sphead->reset_lex(thd);
+ if (Lex->sphead->reset_lex(thd))
+ {
+ /*
+ Failed to allocate memory or something else really bad
+ happened.
+ */
+ MYSQL_YYABORT;
+ }
lex= thd->lex;
/* Set new LEX as if we at start of set rule. */
@@ -9832,6 +9850,8 @@ sp_tail:
/* Order is important here: new - reset - init */
sp= new sp_head();
+ if (sp == NULL)
+ MYSQL_YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->m_type= TYPE_ENUM_PROCEDURE;
| Thread |
|---|
| • bk commit into 5.0 tree (thek:1.2536) BUG#31153 | kpettersson | 22 Oct |