Description:
On some builds join_nested.test produces valgrind warning:
==3414== Invalid read of size 1
==3414== at 0x8249452: String::append(char const*, unsigned) (sql_string.cc:459)
==3414== by 0x83E0ED5: mysql_create_view(THD*, TABLE_LIST*, enum_view_create_mode) (sql_view.cc:652)
==3414== by 0x827089F: mysql_execute_command(THD*) (sql_parse.cc:4985)
==3414== by 0x827168C: mysql_parse(THD*, char const*, unsigned, char const**) (sql_parse.cc:6185)
==3414== by 0x8273E40: dispatch_command(enum_server_command, THD*, char*, unsigned) (sql_parse.cc:1874)
==3414== by 0x827530E: do_command(THD*) (sql_parse.cc:1580)
==3414== by 0x8276475: handle_one_connection (sql_parse.cc:1186)
==3414== by 0x406F19A: start_thread (in /lib/libpthread-2.8.so)
==3414== by 0x41B983D: clone (in /lib/libc-2.8.so)
==3414== Address 0x4e99a73 is not stack'd, malloc'd or (recently) free'd
How to repeat:
No idea: it fails on my local build of mysql-5.0-bugteam tree.
OTOH the root cause of the warning is obvious:
mysql_create_view() calls mysql_register_view() and uses
stack data of mysql_register_view() outside of that function.
mysql_create_view() reads value of views->query.str at:
buff.append(views->query.str, views->query.length);
views->query.str contains pointer to freed (stack) memory
of the mysql_register_view() function local variable buff
(or str, that is same):
static int mysql_register_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode)
{
LEX *lex= thd->lex;
char buff[4096];
String str(buff,(uint32) sizeof(buff), system_charset_info);
...
lex->unit.print(&str);
...
/* fill structure */
view->query.str= str.c_ptr_safe();
view->query.length= str.length();
Suggested fix:
Easiest way to fix that is to move buffer variable declaration
to the function that uses its value (from mysql_register_view()
to mysql_create_view()):
--- old/sql_view.cc 2008-09-13 00:06:32.000000000 +0500
+++ new/sql_view.cc 2008-09-13 00:06:27.000000000 +0500
@@ -27,7 +27,7 @@
const LEX_STRING view_type= { (char*) STRING_WITH_LEN("VIEW") };
static int mysql_register_view(THD *thd, TABLE_LIST *view,
- enum_view_create_mode mode);
+ enum_view_create_mode mode, String &str);
const char *updatable_views_with_limit_names[]= { "NO", "YES", NullS };
TYPELIB updatable_views_with_limit_typelib=
@@ -393,6 +393,8 @@
#endif
SELECT_LEX_UNIT *unit= &lex->unit;
bool res= FALSE;
+ char buff[4096];
+ String str(buff, (uint32) sizeof(buff), system_charset_info);
DBUG_ENTER("mysql_create_view");
/* This is ensured in the parser. */
@@ -610,7 +612,7 @@
goto err;
}
VOID(pthread_mutex_lock(&LOCK_open));
- res= mysql_register_view(thd, view, mode);
+ res= mysql_register_view(thd, view, mode, str);
if (mysql_bin_log.is_open())
{
@@ -743,6 +745,7 @@
thd - thread handler
view - view description
mode - VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
+ str - buffer to keep short-living view->query.str value
RETURN
0 OK
@@ -751,11 +754,9 @@
*/
static int mysql_register_view(THD *thd, TABLE_LIST *view,
- enum_view_create_mode mode)
+ enum_view_create_mode mode, String &str)
{
LEX *lex= thd->lex;
- char buff[4096];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];