Skip to content

Commit 78084fa

Browse files
committed
TSAN: data race on vptr (ctor/dtor vs virtual call)
Read of size 8 at 0x7fecf2e75fc8 by thread T2 (mutexes: write M1318): #0 tpool::thread_pool_generic::submit_task(tpool::task*) /tpool/tpool_generic.cc:823:9 (mariadbd+0x25fd2d2) #1 (anonymous namespace)::aio_uring::thread_routine((anonymous namespace)::aio_uring*) /tpool/aio_liburing.cc:173:20 (mariadbd+0x260b21b) #2 void std::__invoke_impl<void, void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*>(std::__invoke_other, void (*&&)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:61:14 (mariadbd+0x260c62a) #3 std::__invoke_result<void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*>::type std::__invoke<void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*>(void (*&&)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*&&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/invoke.h:96:14 (mariadbd+0x260c4ba) #4 void std::thread::_Invoker<std::tuple<void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:253:13 (mariadbd+0x260c442) #5 std::thread::_Invoker<std::tuple<void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*> >::operator()() /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:260:11 (mariadbd+0x260c3c5) #6 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)((anonymous namespace)::aio_uring*), (anonymous namespace)::aio_uring*> > >::_M_run() /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/std_thread.h:211:13 (mariadbd+0x260c189) #7 <null> <null> (libstdc++.so.6+0xd230f) Previous write of size 8 at 0x7fecf2e75fc8 by main thread: #0 tpool::task::task(void (*)(void*), void*, tpool::task_group*) /tpool/task.cc:40:46 (mariadbd+0x260a138) #1 tpool::aiocb::aiocb() /tpool/tpool.h:147:13 (mariadbd+0x2355943) #2 void std::_Construct<tpool::aiocb>(tpool::aiocb*) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_construct.h:109:38 (mariadbd+0x2355845) #3 tpool::aiocb* std::__uninitialized_default_n_1<false>::__uninit_default_n<tpool::aiocb*, unsigned long>(tpool::aiocb*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:579:3 (mariadbd+0x235576c) #4 tpool::aiocb* std::__uninitialized_default_n<tpool::aiocb*, unsigned long>(tpool::aiocb*, unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:638:14 (mariadbd+0x23556e9) #5 tpool::aiocb* std::__uninitialized_default_n_a<tpool::aiocb*, unsigned long, tpool::aiocb>(tpool::aiocb*, unsigned long, std::allocator<tpool::aiocb>&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_uninitialized.h:704:14 (mariadbd+0x2355641) #6 std::vector<tpool::aiocb, std::allocator<tpool::aiocb> >::_M_default_initialize(unsigned long) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:1606:4 (mariadbd+0x2354f3d) #7 std::vector<tpool::aiocb, std::allocator<tpool::aiocb> >::vector(unsigned long, std::allocator<tpool::aiocb> const&) /usr/lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_vector.h:512:9 (mariadbd+0x2354a19) MariaDB#8 tpool::cache<tpool::aiocb>::cache(unsigned long, tpool::cache_notification_mode) /tpool/tpool_structs.h:73:20 (mariadbd+0x2354784) MariaDB#9 io_slots::io_slots(int, int) /storage/innobase/os/os0file.cc:93:3 (mariadbd+0x235343b) MariaDB#10 os_aio_init() /storage/innobase/os/os0file.cc:3780:22 (mariadbd+0x234ebce) MariaDB#11 srv_start(bool) /storage/innobase/srv/srv0start.cc:1190:6 (mariadbd+0x256720c) MariaDB#12 innodb_init(void*) /storage/innobase/handler/ha_innodb.cc:4188:8 (mariadbd+0x1ed3bda) MariaDB#13 ha_initialize_handlerton(st_plugin_int*) /sql/handler.cc:659:31 (mariadbd+0xf7be06) MariaDB#14 plugin_initialize(st_mem_root*, st_plugin_int*, int*, char**, bool) /sql/sql_plugin.cc:1463:9 (mariadbd+0x160fa1b) MariaDB#15 plugin_init(int*, char**, int) /sql/sql_plugin.cc:1756:15 (mariadbd+0x160f07f) MariaDB#16 init_server_components() /sql/mysqld.cc:5043:7 (mariadbd+0xd70fb2) MariaDB#17 mysqld_main(int, char**) /sql/mysqld.cc:5655:7 (mariadbd+0xd6a9d7) MariaDB#18 main /sql/main.cc:34:10 (mariadbd+0xd65d18) I think the report is incorrect: it's not possible to have such a race condition. I've checked it by reading the code and putting assertions. Namely, no aio I/O is possible before the end of os_aio_init(). Most probably it's some bug in TSAN. But the patch fixes around 5 related reports and this is a step toward TSAN usefullness. Currently it reports too much noise. std::unique_ptr is a step toward https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#r11-avoid-calling-new-and-delete-explicitly There is no std::make_unique() in C++11, however.
1 parent a604212 commit 78084fa

File tree

1 file changed

+14
-10
lines changed

1 file changed

+14
-10
lines changed

storage/innobase/os/os0file.cc

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Created 10/21/1995 Heikki Tuuri
8080

8181
#include <thread>
8282
#include <chrono>
83+
#include <memory>
8384

8485
/* Per-IO operation environment*/
8586
class io_slots
@@ -133,8 +134,8 @@ class io_slots
133134
}
134135
};
135136

136-
static io_slots *read_slots;
137-
static io_slots *write_slots;
137+
static std::unique_ptr<io_slots> read_slots;
138+
static std::unique_ptr<io_slots> write_slots;
138139

139140
/** Number of retries for partial I/O's */
140141
constexpr ulint NUM_RETRIES_ON_PARTIAL_IO = 10;
@@ -3744,6 +3745,10 @@ int os_aio_init()
37443745
int max_read_events= int(srv_n_read_io_threads *
37453746
OS_AIO_N_PENDING_IOS_PER_THREAD);
37463747
int max_events= max_read_events + max_write_events;
3748+
3749+
read_slots.reset(new io_slots(max_read_events, srv_n_read_io_threads));
3750+
write_slots.reset(new io_slots(max_write_events, srv_n_write_io_threads));
3751+
37473752
int ret;
37483753
#if LINUX_NATIVE_AIO
37493754
if (srv_use_native_aio && !is_linux_native_aio_supported())
@@ -3774,22 +3779,21 @@ int os_aio_init()
37743779
}
37753780
#endif
37763781

3777-
if (!ret)
3782+
if (ret)
37783783
{
3779-
read_slots= new io_slots(max_read_events, srv_n_read_io_threads);
3780-
write_slots= new io_slots(max_write_events, srv_n_write_io_threads);
3784+
read_slots.reset();
3785+
write_slots.reset();
37813786
}
3787+
37823788
return ret;
37833789
}
37843790

37853791

37863792
void os_aio_free()
37873793
{
37883794
srv_thread_pool->disable_aio();
3789-
delete read_slots;
3790-
delete write_slots;
3791-
read_slots= nullptr;
3792-
write_slots= nullptr;
3795+
read_slots.reset();
3796+
write_slots.reset();
37933797
}
37943798

37953799
/** Wait until there are no pending asynchronous writes. */
@@ -3879,7 +3883,7 @@ dberr_t os_aio(const IORequest &type, void *buf, os_offset_t offset, size_t n)
38793883
}
38803884

38813885
compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN);
3882-
io_slots* slots= type.is_read() ? read_slots : write_slots;
3886+
io_slots* slots= type.is_read() ? read_slots.get() : write_slots.get();
38833887
tpool::aiocb* cb = slots->acquire();
38843888

38853889
cb->m_buffer = buf;

0 commit comments

Comments
 (0)