MDEV-30936 clang 15.0.7 -fsanitize=memory fails massively

handle_slave_io(), handle_slave_sql(), os_thread_exit():
Remove a redundant pthread_exit(nullptr) call, because it
would cause SIGSEGV.

mysql_print_status(): Add MEM_MAKE_DEFINED() to work around
some missing instrumentation around mallinfo2().

que_graph_free_stat_list(): Invoke que_node_get_next(node) before
que_graph_free_recursive(node). That is the logical and
MSAN_OPTIONS=poison_in_dtor=1 compatible way of freeing memory.

ins_node_t::~ins_node_t(): Invoke mem_heap_free(entry_sys_heap).

que_graph_free_recursive(): Rely on ins_node_t::~ins_node_t().

fts_t::~fts_t(): Invoke mem_heap_free(fts_heap).

fts_free(): Replace with direct calls to fts_t::~fts_t().

The failures in free_root() due to MSAN_OPTIONS=poison_in_dtor=1
will be covered in MDEV-30942.
This commit is contained in:
Marko Mäkelä 2023-03-28 11:44:24 +03:00
parent a8b616d1e9
commit dfa90257f6
17 changed files with 32 additions and 63 deletions

View File

@ -5060,8 +5060,7 @@ err_during_init:
DBUG_LEAVE; // Must match DBUG_ENTER() DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end(); my_thread_end();
ERR_remove_state(0); ERR_remove_state(0);
pthread_exit(0); return nullptr;
return 0; // Avoid compiler warnings
} }
/* /*
@ -5766,8 +5765,7 @@ err_during_init:
DBUG_LEAVE; // Must match DBUG_ENTER() DBUG_LEAVE; // Must match DBUG_ENTER()
my_thread_end(); my_thread_end();
ERR_remove_state(0); ERR_remove_state(0);
pthread_exit(0); return nullptr;
return 0; // Avoid compiler warnings
} }

View File

@ -623,6 +623,10 @@ Next alarm time: %lu\n",
#elif defined(HAVE_MALLINFO) #elif defined(HAVE_MALLINFO)
struct mallinfo info= mallinfo(); struct mallinfo info= mallinfo();
#endif #endif
#if __has_feature(memory_sanitizer)
/* Work around missing MSAN instrumentation */
MEM_MAKE_DEFINED(&info, sizeof info);
#endif
#if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2) #if defined(HAVE_MALLINFO) || defined(HAVE_MALLINFO2)
char llbuff[10][22]; char llbuff[10][22];
printf("\nMemory status:\n\ printf("\nMemory status:\n\

View File

@ -2465,9 +2465,7 @@ next:
my_thread_end(); my_thread_end();
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */ thread should always use that to exit and not use return() to exit. */
os_thread_exit(); return os_thread_exit();
OS_THREAD_DUMMY_RETURN;
} }
/** Initialize page_cleaner. */ /** Initialize page_cleaner. */

View File

@ -1962,8 +1962,8 @@ void dict_sys_t::remove(dict_table_t* table, bool lru, bool keep)
#ifdef BTR_CUR_HASH_ADAPT #ifdef BTR_CUR_HASH_ADAPT
if (table->fts) { if (table->fts) {
fts_optimize_remove_table(table); fts_optimize_remove_table(table);
fts_free(table); table->fts->~fts_t();
table->fts = NULL; table->fts = nullptr;
} }
table->autoinc_mutex.lock(); table->autoinc_mutex.lock();

View File

@ -3092,7 +3092,8 @@ func_exit:
/* the table->fts could be created in dict_load_column /* the table->fts could be created in dict_load_column
when a user defined FTS_DOC_ID is present, but no when a user defined FTS_DOC_ID is present, but no
FTS */ FTS */
fts_free(table); table->fts->~fts_t();
table->fts = nullptr;
} else if (fts_optimize_wq) { } else if (fts_optimize_wq) {
fts_optimize_add_table(table); fts_optimize_add_table(table);
} else if (table->can_be_evicted) { } else if (table->can_be_evicted) {

View File

@ -224,7 +224,7 @@ dict_mem_table_free(
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID) || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) { || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
if (table->fts) { if (table->fts) {
fts_free(table); table->fts->~fts_t();
} }
} }

View File

@ -2240,9 +2240,7 @@ DECLARE_THREAD(fil_crypt_thread)(void*)
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */ thread should always use that to exit and not use return() to exit. */
os_thread_exit(); return os_thread_exit();
OS_THREAD_DUMMY_RETURN;
} }
/********************************************************************* /*********************************************************************

View File

@ -833,7 +833,8 @@ void fts_clear_all(dict_table_t *table, trx_t *trx)
fts_optimize_remove_table(table); fts_optimize_remove_table(table);
fts_drop_tables(trx, table); fts_drop_tables(trx, table);
fts_free(table); table->fts->~fts_t();
table->fts= nullptr;
DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS); DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS);
} }
@ -5350,14 +5351,14 @@ fts_t::~fts_t()
{ {
ut_ad(add_wq == NULL); ut_ad(add_wq == NULL);
if (cache != NULL) { if (cache) {
fts_cache_clear(cache); fts_cache_clear(cache);
fts_cache_destroy(cache); fts_cache_destroy(cache);
cache = NULL;
} }
/* There is no need to call ib_vector_free() on this->indexes /* There is no need to call ib_vector_free() on this->indexes
because it is stored in this->fts_heap. */ because it is stored in this->fts_heap. */
mem_heap_free(fts_heap);
} }
/*********************************************************************//** /*********************************************************************//**
@ -5380,22 +5381,6 @@ fts_create(
return(fts); return(fts);
} }
/*********************************************************************//**
Free the FTS resources. */
void
fts_free(
/*=====*/
dict_table_t* table) /*!< in/out: table with FTS indexes */
{
fts_t* fts = table->fts;
fts->~fts_t();
mem_heap_free(fts->fts_heap);
table->fts = NULL;
}
/*********************************************************************//** /*********************************************************************//**
Take a FTS savepoint. */ Take a FTS savepoint. */
UNIV_INLINE UNIV_INLINE

View File

@ -12622,7 +12622,8 @@ int create_table_info_t::create_table(bool create_fk)
m_table->name.m_name); m_table->name.m_name);
if (m_table->fts) { if (m_table->fts) {
fts_free(m_table); m_table->fts->~fts_t();
m_table->fts = nullptr;
} }
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0),

View File

@ -1028,7 +1028,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
old_v_cols[i].~dict_v_col_t(); old_v_cols[i].~dict_v_col_t();
} }
if (instant_table->fts) { if (instant_table->fts) {
fts_free(instant_table); instant_table->fts->~fts_t();
instant_table->fts = nullptr;
} }
dict_mem_table_free(instant_table); dict_mem_table_free(instant_table);
} }
@ -8753,7 +8754,8 @@ innobase_rollback_sec_index(
&& !DICT_TF2_FLAG_IS_SET(user_table, && !DICT_TF2_FLAG_IS_SET(user_table,
DICT_TF2_FTS_HAS_DOC_ID) DICT_TF2_FTS_HAS_DOC_ID)
&& !innobase_fulltext_exist(table)) { && !innobase_fulltext_exist(table)) {
fts_free(user_table); user_table->fts->~fts_t();
user_table->fts = nullptr;
} }
} }

View File

@ -607,14 +607,6 @@ fts_create(
dict_table_t* table); /*!< out: table with FTS dict_table_t* table); /*!< out: table with FTS
indexes */ indexes */
/**********************************************************************//**
Free the FTS resources. */
void
fts_free(
/*=====*/
dict_table_t* table); /*!< in/out: table with
FTS indexes */
/*********************************************************************//** /*********************************************************************//**
Run OPTIMIZE on the given table. Run OPTIMIZE on the given table.
@return DB_SUCCESS if all OK */ @return DB_SUCCESS if all OK */

View File

@ -86,7 +86,7 @@ We do not return an error code because if there is one, we crash here. */
os_thread_t os_thread_create(os_thread_func_t func, void *arg= nullptr); os_thread_t os_thread_create(os_thread_func_t func, void *arg= nullptr);
/** Detach and terminate the current thread. */ /** Detach and terminate the current thread. */
ATTRIBUTE_NORETURN void os_thread_exit(); os_thread_ret_t os_thread_exit();
/*****************************************************************//** /*****************************************************************//**
The thread sleeps at least the time given in microseconds. */ The thread sleeps at least the time given in microseconds. */

View File

@ -177,6 +177,7 @@ struct ins_node_t
trx_id(0), entry_sys_heap(mem_heap_create(128)) trx_id(0), entry_sys_heap(mem_heap_create(128))
{ {
} }
~ins_node_t() { mem_heap_free(entry_sys_heap); }
que_common_t common; /*!< node type: QUE_NODE_INSERT */ que_common_t common; /*!< node type: QUE_NODE_INSERT */
ulint ins_type;/* INS_VALUES, INS_SEARCHED, or INS_DIRECT */ ulint ins_type;/* INS_VALUES, INS_SEARCHED, or INS_DIRECT */
dtuple_t* row; /*!< row to insert */ dtuple_t* row; /*!< row to insert */

View File

@ -86,7 +86,7 @@ os_thread_t os_thread_create(os_thread_func_t func, void *arg)
} }
/** Detach and terminate the current thread. */ /** Detach and terminate the current thread. */
ATTRIBUTE_NORETURN void os_thread_exit() os_thread_ret_t os_thread_exit()
{ {
#ifdef UNIV_DEBUG_THREAD_CREATION #ifdef UNIV_DEBUG_THREAD_CREATION
ib::info() << "Thread exits, id " << os_thread_get_curr_id(); ib::info() << "Thread exits, id " << os_thread_get_curr_id();
@ -100,8 +100,8 @@ ATTRIBUTE_NORETURN void os_thread_exit()
ExitThread(0); ExitThread(0);
#else #else
pthread_detach(pthread_self()); pthread_detach(pthread_self());
pthread_exit(NULL);
#endif #endif
OS_THREAD_DUMMY_RETURN;
} }
/*****************************************************************//** /*****************************************************************//**

View File

@ -360,9 +360,9 @@ que_graph_free_stat_list(
que_node_t* node) /*!< in: first query graph node in the list */ que_node_t* node) /*!< in: first query graph node in the list */
{ {
while (node) { while (node) {
que_node_t* next = que_node_get_next(node);
que_graph_free_recursive(node); que_graph_free_recursive(node);
node = next;
node = que_node_get_next(node);
} }
} }
@ -421,19 +421,10 @@ que_graph_free_recursive(
break; break;
case QUE_NODE_INSERT: case QUE_NODE_INSERT:
ins = static_cast<ins_node_t*>(node); ins = static_cast<ins_node_t*>(node);
que_graph_free_recursive(ins->select); que_graph_free_recursive(ins->select);
ins->select = NULL;
ins->~ins_node_t(); ins->~ins_node_t();
if (ins->entry_sys_heap != NULL) {
mem_heap_free(ins->entry_sys_heap);
ins->entry_sys_heap = NULL;
}
break; break;
case QUE_NODE_PURGE: case QUE_NODE_PURGE:
purge = static_cast<purge_node_t*>(node); purge = static_cast<purge_node_t*>(node);

View File

@ -3225,8 +3225,8 @@ row_drop_ancillary_fts_tables(
/* fts_que_graph_free_check_lock would try to acquire /* fts_que_graph_free_check_lock would try to acquire
dict mutex lock */ dict mutex lock */
table->fts->dict_locked = true; table->fts->dict_locked = true;
table->fts->~fts_t();
fts_free(table); table->fts = nullptr;
} }
return(DB_SUCCESS); return(DB_SUCCESS);

View File

@ -845,9 +845,7 @@ DECLARE_THREAD(trx_rollback_all_recovered)(void*)
/* We count the number of threads in os_thread_exit(). A created /* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */ thread should always use that to exit and not use return() to exit. */
os_thread_exit(); return os_thread_exit();
OS_THREAD_DUMMY_RETURN;
} }
/****************************************************************//** /****************************************************************//**