Commit cf858b71 authored by Sujatha Sivakumar's avatar Sujatha Sivakumar

BUG#11762670:MY_B_WRITE RETURN VALUE IGNORED

Problem:
=======
The return value from my_b_write is ignored by: `my_b_write_quoted',
`my_b_write_bit',`Query_log_event::print_query_header'

Most callers of `my_b_printf' ignore the return value. `log_event.cc' 
has many calls to it. 

Analysis:
========
`my_b_write' is used to write data into a file. If the write fails it
sets appropriate error number and error message through my_error()
function call and sets the IO_CACHE::error == -1.
`my_b_printf' function is also used to write data into a file, it
internally invokes my_b_write to do the write operation. Upon
success it returns number of characters written to file and on error
it returns -1 and sets the error through my_error() and also sets
IO_CACHE::error == -1.  Most of the event specific print functions
for example `Create_file_log_event::print', `Execute_load_log_event::print'
etc are the ones which make several calls to the above two functions and
they do not check for the return value after the 'print' call. All the above 
mentioned abuse cases deal with the client side.

Fix:
===
As part of bug fix a check for IO_CACHE::error == -1 has been added at 
a very high level after the call to the 'print' function.  There are 
few more places where the return value of "my_b_write" is ignored
those are mentioned below.

+++ mysys/mf_iocache2.c    2012-06-04 07:03:15 +0000
@@ -430,7 +430,8 @@
           memset(buffz, '0', minimum_width - length2);
         else
           memset(buffz, ' ', minimum_width - length2);
-        my_b_write(info, buffz, minimum_width - length2);

+++ sql/log.cc	2012-06-08 09:04:46 +0000
@@ -2388,7 +2388,12 @@
     {
       end= strxmov(buff, "# administrator command: ", NullS);
       buff_len= (ulong) (end - buff);
-      my_b_write(&log_file, (uchar*) buff, buff_len);

At these places appropriate return value handlers have been added.
parent fcc53fa7
......@@ -784,8 +784,11 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
goto end;
}
else
{
ce->print(result_file, print_event_info, TRUE);
if (head->error == -1)
goto err;
}
// If this binlog is not 3.23 ; why this test??
if (glob_description_event->binlog_version >= 3)
{
......@@ -836,6 +839,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
ce->print(result_file, print_event_info, TRUE);
my_free((char*)ce->fname,MYF(MY_WME));
delete ce;
if (head->error == -1)
goto err;
}
else
warning("Ignoring Execute_load_log_event as there is no "
......@@ -890,6 +895,12 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
{
convert_path_to_forward_slashes(fname);
exlq->print(result_file, print_event_info, fname);
if (head->error == -1)
{
if (fname)
my_free(fname, MYF(MY_WME));
goto err;
}
}
else
warning("Ignoring Execute_load_query since there is no "
......
......@@ -430,7 +430,11 @@ process_flags:
memset(buffz, '0', minimum_width - length2);
else
memset(buffz, ' ', minimum_width - length2);
my_b_write(info, buffz, minimum_width - length2);
if (my_b_write(info, buffz, minimum_width - length2))
{
my_afree(buffz);
goto err;
}
my_afree(buffz);
}
......
......@@ -2388,7 +2388,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
{
end= strxmov(buff, "# administrator command: ", NullS);
buff_len= (ulong) (end - buff);
my_b_write(&log_file, (uchar*) buff, buff_len);
DBUG_EXECUTE_IF("simulate_slow_log_write_error",
{DBUG_SET("+d,simulate_file_write_error");});
if(my_b_write(&log_file, (uchar*) buff, buff_len))
tmp_errno= errno;
}
if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
my_b_write(&log_file, (uchar*) ";\n",2) ||
......
......@@ -6312,11 +6312,18 @@ void Create_file_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info
{
Load_log_event::print(file, print_event_info,
!check_fname_outside_temp_buf());
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
*/
my_b_printf(&cache, "#");
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
*/
DBUG_EXECUTE_IF ("simulate_create_event_write_error",
{(&cache)->write_pos= (&cache)->write_end;
DBUG_SET("+d,simulate_file_write_error");});
/*
That one is for "file_id: etc" below: in mysqlbinlog we want the #, in
SHOW BINLOG EVENTS we don't.
*/
my_b_printf(&cache, "#");
}
my_b_printf(&cache, " file_id: %d block_len: %d\n", file_id, block_len);
......@@ -6992,6 +6999,13 @@ void Execute_load_query_log_event::print(FILE* file,
Write_on_release_cache cache(&print_event_info->head_cache, file);
print_query_header(&cache, print_event_info);
/**
reduce the size of io cache so that the write function is called
for every call to my_b_printf().
*/
DBUG_EXECUTE_IF ("simulate_execute_event_write_error",
{(&cache)->write_pos= (&cache)->write_end;
DBUG_SET("+d,simulate_file_write_error");});
if (local_fname)
{
......
......@@ -300,7 +300,7 @@ private:
public:
Deferred_log_events(Relay_log_info *rli);
~Deferred_log_events();
/* queue for exection at Query-log-event time prior the Query */;
/* queue for exection at Query-log-event time prior the Query */
int add(Log_event *ev);
bool is_empty();
bool execute(Relay_log_info *rli);
......
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