Skip to content

Commit e49e52a

Browse files
jhauglidTor Didriksen
authored andcommitted
Bug#24343330: READ OF OUT-OF-SCOPE (TEMPFILE) IN MYSQL_UPDATE()
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)
1 parent 4582a90 commit e49e52a

File tree

1 file changed

+15
-16
lines changed

1 file changed

+15
-16
lines changed

sql/sql_update.cc

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -644,15 +644,9 @@ bool mysql_update(THD *thd,
644644
*/
645645
table->prepare_for_position();
646646

647-
IO_CACHE tempfile;
648-
if (open_cached_file(&tempfile, mysql_tmpdir,TEMP_PREFIX,
649-
DISK_BUFFER_SIZE, MYF(MY_WME)))
650-
goto exit_without_my_ok;
651-
652647
/* If quick select is used, initialize it before retrieving rows. */
653648
if (qep_tab.quick() && (error= qep_tab.quick()->reset()))
654649
{
655-
close_cached_file(&tempfile);
656650
if (table->file->is_fatal_error(error))
657651
error_flags|= ME_FATALERROR;
658652

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

680674
if (error)
681-
{
682-
close_cached_file(&tempfile); /* purecov: inspected */
683675
goto exit_without_my_ok;
684-
}
685676

686677
THD_STAGE_INFO(thd, stage_searching_rows_for_update);
687678
ha_rows tmp_limit= limit;
688679

680+
IO_CACHE *tempfile= (IO_CACHE*) my_malloc(key_memory_TABLE_sort_io_cache,
681+
sizeof(IO_CACHE),
682+
MYF(MY_FAE | MY_ZEROFILL));
683+
684+
if (open_cached_file(tempfile, mysql_tmpdir,TEMP_PREFIX,
685+
DISK_BUFFER_SIZE, MYF(MY_WME)))
686+
{
687+
my_free(tempfile);
688+
goto exit_without_my_ok;
689+
}
690+
689691
while (!(error=info.read_record(&info)) && !thd->killed)
690692
{
691693
thd->inc_examined_row_count(1);
@@ -705,7 +707,7 @@ bool mysql_update(THD *thd,
705707
continue; /* repeat the read of the same row if it still exists */
706708

707709
table->file->position(table->record[0]);
708-
if (my_b_write(&tempfile,table->file->ref,
710+
if (my_b_write(tempfile, table->file->ref,
709711
table->file->ref_length))
710712
{
711713
error=1; /* purecov: inspected */
@@ -726,19 +728,16 @@ bool mysql_update(THD *thd,
726728
table->file->try_semi_consistent_read(0);
727729
end_read_record(&info);
728730
/* Change select to use tempfile */
729-
if (reinit_io_cache(&tempfile,READ_CACHE,0L,0,0))
731+
if (reinit_io_cache(tempfile, READ_CACHE, 0L, 0, 0))
730732
error=1; /* purecov: inspected */
731-
// Read row ptrs from this file.
733+
732734
DBUG_ASSERT(table->sort.io_cache == NULL);
733-
table->sort.io_cache= (IO_CACHE*) my_malloc(key_memory_TABLE_sort_io_cache,
734-
sizeof(IO_CACHE),
735-
MYF(MY_FAE | MY_ZEROFILL));
736735
/*
737736
After this assignment, init_read_record() will run, and decide to
738737
read from sort.io_cache. This cache will be freed when qep_tab is
739738
destroyed.
740739
*/
741-
*table->sort.io_cache= tempfile;
740+
table->sort.io_cache= tempfile;
742741
qep_tab.set_quick(NULL);
743742
qep_tab.set_condition(NULL);
744743
if (error >= 0)

0 commit comments

Comments
 (0)