Skip to content

Commit

Permalink
Bug#24343330: READ OF OUT-OF-SCOPE (TEMPFILE) IN MYSQL_UPDATE()
Browse files Browse the repository at this point in the history
The problem was that an IO_CACHE variable used during UPDATE,
was allocated on the stack and later copyied into a heap
allocated variable. However, the pointers inside this struct
was not adjusted, so that they still pointed to the stack.
After the stack frame ended, they became invalid.

This patch fixes the problem by allocating the IO_CACHE on
the heap instead and copying the pointer to this IO_CACHE
struct, rather than copying the contents of the struct.

Issue identified by the new ASAN option
-fsanitize-address-use-after-scope

(cherry picked from commit d3bff0c03637119f960c7d3db67a85912bc37e4a)
  • Loading branch information
jhauglid authored and Tor Didriksen committed Nov 10, 2017
1 parent 4582a90 commit e49e52a
Showing 1 changed file with 15 additions and 16 deletions.
31 changes: 15 additions & 16 deletions sql/sql_update.cc
Expand Up @@ -644,15 +644,9 @@ bool mysql_update(THD *thd,
*/
table->prepare_for_position();

IO_CACHE tempfile;
if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(MY_WME)))
goto exit_without_my_ok;

/* If quick select is used, initialize it before retrieving rows. */
if (qep_tab.quick() && (error= qep_tab.quick()->reset()))
{
close_cached_file(&tempfile);
if (table->file->is_fatal_error(error))
error_flags|= ME_FATALERROR;

Expand All @@ -678,14 +672,22 @@ bool mysql_update(THD *thd,
error= init_read_record_idx(&info, thd, table, 1, used_index, reverse);

if (error)
{
close_cached_file(&tempfile); /* purecov: inspected */
goto exit_without_my_ok;
}

THD_STAGE_INFO(thd, stage_searching_rows_for_update);
ha_rows tmp_limit= limit;

IO_CACHE *tempfile= (IO_CACHE*) my_malloc(key_memory_TABLE_sort_io_cache,
sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));

if (open_cached_file(tempfile, mysql_tmpdir,TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(MY_WME)))
{
my_free(tempfile);
goto exit_without_my_ok;
}

while (!(error=info.read_record(&info)) && !thd->killed)
{
thd->inc_examined_row_count(1);
Expand All @@ -705,7 +707,7 @@ bool mysql_update(THD *thd,
continue; /* repeat the read of the same row if it still exists */

table->file->position(table->record[0]);
if (my_b_write(&tempfile,table->file->ref,
if (my_b_write(tempfile, table->file->ref,
table->file->ref_length))
{
error=1; /* purecov: inspected */
Expand All @@ -726,19 +728,16 @@ bool mysql_update(THD *thd,
table->file->try_semi_consistent_read(0);
end_read_record(&info);
/* Change select to use tempfile */
if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
if (reinit_io_cache(tempfile, READ_CACHE, 0L, 0, 0))
error=1; /* purecov: inspected */
// Read row ptrs from this file.

DBUG_ASSERT(table->sort.io_cache == NULL);
table->sort.io_cache= (IO_CACHE*) my_malloc(key_memory_TABLE_sort_io_cache,
sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
/*
After this assignment, init_read_record() will run, and decide to
read from sort.io_cache. This cache will be freed when qep_tab is
destroyed.
*/
*table->sort.io_cache= tempfile;
table->sort.io_cache= tempfile;
qep_tab.set_quick(NULL);
qep_tab.set_condition(NULL);
if (error >= 0)
Expand Down

0 comments on commit e49e52a

Please sign in to comment.