Skip to content

Commit b4287f9

Browse files
committed
Bug#23550835 ITERATING ON A FULL PERFORMANCE SCHEMA BUFFER CAN CRASH
Before this fix, a SELECT on performance schema tables could crash the server, when an internal buffer is full. This could happen for example with: - more than 2^20 tables - more than 2^20 indexes - more than 2^20 files The immediate root cause is that using PFS_buffer_scalable_iterator on a full buffer causes an overflow in PFS_buffer_scalable_container::scan_next(), by accessing a page outside of m_pages[] This has been fixed by changing the do {} while loop into a while {} loop. For robustness, other do while loops have been changed to use the same while {} pattern, which is more tolerant to edge cases, and therefore less risky for maintenance. While investigating this issue, another case of overflow was found in the code: every page in the scalable buffer is of size PFS_PAGE_SIZE, ** except ** the last page, which can be smaller, due to m_last_page_size. The problem is that every code that iterate on pages, for example PFS_buffer_scalable_container::apply(), expects page to have a size of PFS_PAGE_SIZE, and cause corruption when using a partial last page. The fix is to: - make each page aware of its own size, with PFS_buffer_default_array::m_max, - iterate from PFS_buffer_default_array::get_first() to PFS_buffer_default_array::get_last(), instead of using [0, PFS_PAGE_SIZE[ Also, logic for iterators need to be aware of partial pages, with tests such as "if (index_2 >= page->m_max)", in PFS_buffer_scalable_container::get(). Lastly, the hard coded theoretical size limit on some buffers has been raised, since it was reached in practice for some workloads. New limits are: - 16 million instrumented tables (2^24), increased from 1M (2^20) - 64 million instrumented indexes (2^26), increased from 1M (2^20) - 16 million instrumented files (2^24), increased from 1M (2^20)
1 parent a574ded commit b4287f9

File tree

2 files changed

+104
-71
lines changed

2 files changed

+104
-71
lines changed

storage/perfschema/pfs_buffer_container.cc

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -64,8 +64,9 @@ PFS_program_container global_program_container(& default_program_allocator);
6464
PFS_buffer_default_allocator<PFS_prepared_stmt> default_prepared_stmt_allocator(& builtin_memory_prepared_stmt);
6565
PFS_prepared_stmt_container global_prepared_stmt_container(& default_prepared_stmt_allocator);
6666

67-
int PFS_account_allocator::alloc_array(PFS_account_array *array, size_t size)
67+
int PFS_account_allocator::alloc_array(PFS_account_array *array)
6868
{
69+
size_t size= array->m_max;
6970
size_t index;
7071
size_t waits_sizing= size * wait_class_max;
7172
size_t stages_sizing= size * stage_class_max;
@@ -168,8 +169,9 @@ int PFS_account_allocator::alloc_array(PFS_account_array *array, size_t size)
168169
return 0;
169170
}
170171

171-
void PFS_account_allocator::free_array(PFS_account_array *array, size_t size)
172+
void PFS_account_allocator::free_array(PFS_account_array *array)
172173
{
174+
size_t size= array->m_max;
173175
size_t waits_sizing= size * wait_class_max;
174176
size_t stages_sizing= size * stage_class_max;
175177
size_t statements_sizing= size * statement_class_max;
@@ -209,8 +211,9 @@ void PFS_account_allocator::free_array(PFS_account_array *array, size_t size)
209211
PFS_account_allocator account_allocator;
210212
PFS_account_container global_account_container(& account_allocator);
211213

212-
int PFS_host_allocator::alloc_array(PFS_host_array *array, size_t size)
214+
int PFS_host_allocator::alloc_array(PFS_host_array *array)
213215
{
216+
size_t size= array->m_max;
214217
PFS_host *pfs;
215218
size_t index;
216219
size_t waits_sizing= size * wait_class_max;
@@ -316,8 +319,9 @@ int PFS_host_allocator::alloc_array(PFS_host_array *array, size_t size)
316319
return 0;
317320
}
318321

319-
void PFS_host_allocator::free_array(PFS_host_array *array, size_t size)
322+
void PFS_host_allocator::free_array(PFS_host_array *array)
320323
{
324+
size_t size= array->m_max;
321325
size_t waits_sizing= size * wait_class_max;
322326
size_t stages_sizing= size * stage_class_max;
323327
size_t statements_sizing= size * statement_class_max;
@@ -357,8 +361,9 @@ void PFS_host_allocator::free_array(PFS_host_array *array, size_t size)
357361
PFS_host_allocator host_allocator;
358362
PFS_host_container global_host_container(& host_allocator);
359363

360-
int PFS_thread_allocator::alloc_array(PFS_thread_array *array, size_t size)
364+
int PFS_thread_allocator::alloc_array(PFS_thread_array *array)
361365
{
366+
size_t size= array->m_max;
362367
PFS_thread *pfs;
363368
PFS_events_statements *pfs_stmt;
364369
unsigned char *pfs_tokens;
@@ -614,8 +619,9 @@ int PFS_thread_allocator::alloc_array(PFS_thread_array *array, size_t size)
614619
return 0;
615620
}
616621

617-
void PFS_thread_allocator::free_array(PFS_thread_array *array, size_t size)
622+
void PFS_thread_allocator::free_array(PFS_thread_array *array)
618623
{
624+
size_t size= array->m_max;
619625
size_t waits_sizing= size * wait_class_max;
620626
size_t stages_sizing= size * stage_class_max;
621627
size_t statements_sizing= size * statement_class_max;
@@ -718,8 +724,9 @@ void PFS_thread_allocator::free_array(PFS_thread_array *array, size_t size)
718724
PFS_thread_allocator thread_allocator;
719725
PFS_thread_container global_thread_container(& thread_allocator);
720726

721-
int PFS_user_allocator::alloc_array(PFS_user_array *array, size_t size)
727+
int PFS_user_allocator::alloc_array(PFS_user_array *array)
722728
{
729+
size_t size= array->m_max;
723730
PFS_user *pfs;
724731
size_t index;
725732
size_t waits_sizing= size * wait_class_max;
@@ -825,8 +832,9 @@ int PFS_user_allocator::alloc_array(PFS_user_array *array, size_t size)
825832
return 0;
826833
}
827834

828-
void PFS_user_allocator::free_array(PFS_user_array *array, size_t size)
835+
void PFS_user_allocator::free_array(PFS_user_array *array)
829836
{
837+
size_t size= array->m_max;
830838
size_t waits_sizing= size * wait_class_max;
831839
size_t stages_sizing= size * stage_class_max;
832840
size_t statements_sizing= size * statement_class_max;

0 commit comments

Comments
 (0)