diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-01 17:23:00 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-07-01 17:23:00 +0300 |
commit | c36834c8324974f26770d64192898f4f45d9f772 (patch) | |
tree | 772101777e3754b53bf752c25e93b9b8638ac0f3 /storage/innobase/row | |
parent | 5a097c5556dffc1aec73616f58cecf9345d96050 (diff) | |
download | mariadb-git-c36834c8324974f26770d64192898f4f45d9f772.tar.gz |
MDEV-20377: Make WITH_MSAN more usable
MemorySanitizer (clang -fsanitize=memory) requires that all code
be compiled with instrumentation enabled. The only exception is the
C runtime library. Failure to use instrumented libraries will cause
bogus messages about memory being uninitialized.
In WITH_MSAN builds, we must avoid calling getservbyname(),
because even though it is a standard library function, it is
not instrumented, not even in clang 10.
Note: Before MariaDB Server 10.5, ./mtr will typically fail
due to the old PCRE library, which was updated in MDEV-14024.
The following cmake options were tested on 10.5
in commit 94d0bb4dbeb28a94d1f87fdd55f4297ff3df0157:
cmake \
-DCMAKE_C_FLAGS='-march=native -O2' \
-DCMAKE_CXX_FLAGS='-stdlib=libc++ -march=native -O2' \
-DWITH_EMBEDDED_SERVER=OFF -DWITH_UNIT_TESTS=OFF -DCMAKE_BUILD_TYPE=Debug \
-DWITH_INNODB_{BZIP2,LZ4,LZMA,LZO,SNAPPY}=OFF \
-DPLUGIN_{ARCHIVE,TOKUDB,MROONGA,OQGRAPH,ROCKSDB,CONNECT,SPIDER}=NO \
-DWITH_SAFEMALLOC=OFF \
-DWITH_{ZLIB,SSL,PCRE}=bundled \
-DHAVE_LIBAIO_H=0 \
-DWITH_MSAN=ON
MEM_MAKE_DEFINED(): An alias for VALGRIND_MAKE_MEM_DEFINED()
and __msan_unpoison().
MEM_GET_VBITS(), MEM_SET_VBITS(): Aliases for
VALGRIND_GET_VBITS(), VALGRIND_SET_VBITS(), __msan_copy_shadow().
InnoDB: Replace the UNIV_MEM_ macros with corresponding MEM_ macros.
ut_crc32_8_hw(), ut_crc32_64_low_hw(): Use the compiler built-in
functions instead of inline assembler when building WITH_MSAN.
This will require at least -msse4.2 when building for IA-32 or AMD64.
The inline assembler would not be instrumented, and would thus cause
bogus failures.
Diffstat (limited to 'storage/innobase/row')
-rw-r--r-- | storage/innobase/row/row0ext.cc | 6 | ||||
-rw-r--r-- | storage/innobase/row/row0ftsort.cc | 10 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 6 | ||||
-rw-r--r-- | storage/innobase/row/row0log.cc | 40 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.cc | 41 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 4 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 38 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 4 |
8 files changed, 91 insertions, 58 deletions
diff --git a/storage/innobase/row/row0ext.cc b/storage/innobase/row/row0ext.cc index f7e28981939..32e9aad9896 100644 --- a/storage/innobase/row/row0ext.cc +++ b/storage/innobase/row/row0ext.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -119,11 +120,6 @@ row_ext_create( ret->buf = static_cast<byte*>( mem_heap_alloc(heap, n_ext * ret->max_len)); -#ifdef UNIV_DEBUG - memset(ret->buf, 0xaa, n_ext * ret->max_len); - UNIV_MEM_ALLOC(ret->buf, n_ext * ret->max_len); -#endif - /* Fetch the BLOB prefixes */ for (i = 0; i < n_ext; i++) { const dfield_t* dfield; diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc index c7c86fb337b..4085ff17bd3 100644 --- a/storage/innobase/row/row0ftsort.cc +++ b/storage/innobase/row/row0ftsort.cc @@ -903,7 +903,7 @@ loop: goto func_exit; } - UNIV_MEM_INVALID(block[t_ctx.buf_used], srv_sort_buf_size); + MEM_UNDEFINED(block[t_ctx.buf_used], srv_sort_buf_size); buf[t_ctx.buf_used] = row_merge_buf_empty(buf[t_ctx.buf_used]); mycount[t_ctx.buf_used] += t_ctx.rows_added[t_ctx.buf_used]; t_ctx.rows_added[t_ctx.buf_used] = 0; @@ -997,12 +997,14 @@ exit: goto func_exit; } - UNIV_MEM_INVALID(block[i], srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(block[i], srv_sort_buf_size); if (crypt_block[i]) { - UNIV_MEM_INVALID(crypt_block[i], - srv_sort_buf_size); + MEM_UNDEFINED(crypt_block[i], + srv_sort_buf_size); } +#endif /* HAVE_valgrind_or_MSAN */ } buf[i] = row_merge_buf_empty(buf[i]); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 2ca54e90c4e..50394193a15 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -1272,8 +1272,10 @@ row_ins_foreign_check_on_constraint( update->info_bits = 0; update->n_fields = foreign->n_fields; - UNIV_MEM_INVALID(update->fields, - update->n_fields * sizeof *update->fields); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(update->fields, + update->n_fields * sizeof *update->fields); +#endif /* HAVE_valgrind_or_MSAN */ bool affects_fulltext = false; diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index e46ee2c4f18..986cac54540 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -323,7 +323,9 @@ row_log_online_op( goto err_exit; } - UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.buf, sizeof log->tail.buf); +#endif /* HAVE_valgrind_or_MSAN */ ut_ad(log->tail.bytes < srv_sort_buf_size); avail_size = srv_sort_buf_size - log->tail.bytes; @@ -373,7 +375,7 @@ row_log_online_op( log->tail.buf, avail_size); } - UNIV_MEM_ASSERT_RW(buf, srv_sort_buf_size); + MEM_CHECK_DEFINED(buf, srv_sort_buf_size); if (row_log_tmpfile(log) < 0) { log->error = DB_OUT_OF_MEMORY; @@ -407,8 +409,10 @@ write_failed: index->type |= DICT_CORRUPT; } - UNIV_MEM_INVALID(log->tail.block, srv_sort_buf_size); - UNIV_MEM_INVALID(buf, srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.block, srv_sort_buf_size); + MEM_UNDEFINED(buf, srv_sort_buf_size); +#endif /* HAVE_valgrind_or_MSAN */ memcpy(log->tail.block, log->tail.buf + avail_size, mrec_size - avail_size); @@ -418,7 +422,9 @@ write_failed: ut_ad(b == log->tail.block + log->tail.bytes); } - UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.buf, sizeof log->tail.buf); +#endif /* HAVE_valgrind_or_MSAN */ err_exit: mutex_exit(&log->mutex); } @@ -450,7 +456,9 @@ row_log_table_open( { mutex_enter(&log->mutex); - UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.buf, sizeof log->tail.buf); +#endif /* HAVE_valgrind_or_MSAN */ if (log->error != DB_SUCCESS) { err_exit: @@ -510,7 +518,7 @@ row_log_table_close_func( memcpy(buf + log->tail.bytes, log->tail.buf, avail); } - UNIV_MEM_ASSERT_RW(buf, srv_sort_buf_size); + MEM_CHECK_DEFINED(buf, srv_sort_buf_size); if (row_log_tmpfile(log) < 0) { log->error = DB_OUT_OF_MEMORY; @@ -541,8 +549,10 @@ row_log_table_close_func( write_failed: log->error = DB_ONLINE_LOG_TOO_BIG; } - UNIV_MEM_INVALID(log->tail.block, srv_sort_buf_size); - UNIV_MEM_INVALID(buf, srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.block, srv_sort_buf_size); + MEM_UNDEFINED(buf, srv_sort_buf_size); +#endif /* HAVE_valgrind_or_MSAN */ memcpy(log->tail.block, log->tail.buf + avail, size - avail); log->tail.bytes = size - avail; } else { @@ -551,7 +561,9 @@ write_failed: } log->tail.total += size; - UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(log->tail.buf, sizeof log->tail.buf); +#endif /* HAVE_valgrind_or_MSAN */ err_exit: mutex_exit(&log->mutex); @@ -2557,7 +2569,9 @@ row_log_table_apply_ops( ut_ad(new_trx_id_col > 0); ut_ad(new_trx_id_col != ULINT_UNDEFINED); - UNIV_MEM_INVALID(&mrec_end, sizeof mrec_end); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&mrec_end, sizeof mrec_end); +#endif /* HAVE_valgrind_or_MSAN */ offsets = static_cast<rec_offs*>(ut_malloc_nokey(i * sizeof *offsets)); rec_offs_set_n_alloc(offsets, i); @@ -3434,7 +3448,9 @@ row_log_apply_ops( ut_ad(!index->is_committed()); ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_X)); ut_ad(index->online_log); - UNIV_MEM_INVALID(&mrec_end, sizeof mrec_end); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&mrec_end, sizeof mrec_end); +#endif /* HAVE_valgrind_or_MSAN */ offsets = static_cast<rec_offs*>(ut_malloc_nokey(i * sizeof *offsets)); rec_offs_set_n_alloc(offsets, i); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 5cbfe0e3ddb..3a6d8cea4a8 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -1027,11 +1027,11 @@ row_merge_buf_write( ut_a(b < &block[srv_sort_buf_size]); ut_a(b == &block[0] + buf->total_size); *b++ = 0; -#ifdef UNIV_DEBUG_VALGRIND +#ifdef HAVE_valgrind_or_MSAN /* The rest of the block is uninitialized. Initialize it to avoid bogus warnings. */ memset(b, 0xff, &block[srv_sort_buf_size] - b); -#endif /* UNIV_DEBUG_VALGRIND */ +#endif /* HAVE_valgrind_or_MSAN */ DBUG_LOG("ib_merge_sort", "write " << reinterpret_cast<const void*>(b) << ',' << of->fd << ',' << of->offset << " EOF"); @@ -1425,7 +1425,9 @@ row_merge_write_rec( return(NULL); } - UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&block[0], srv_sort_buf_size); +#endif /* HAVE_valgrind_or_MSAN */ /* Copy the rest. */ b = &block[0]; @@ -1466,20 +1468,19 @@ row_merge_write_eof( ",fd=" << fd << ',' << *foffs); *b++ = 0; - UNIV_MEM_ASSERT_RW(&block[0], b - &block[0]); - UNIV_MEM_ASSERT_W(&block[0], srv_sort_buf_size); + MEM_CHECK_DEFINED(&block[0], b - &block[0]); + MEM_CHECK_ADDRESSABLE(&block[0], srv_sort_buf_size); -#ifdef UNIV_DEBUG_VALGRIND - /* The rest of the block is uninitialized. Initialize it - to avoid bogus warnings. */ - memset(b, 0xff, &block[srv_sort_buf_size] - b); -#endif /* UNIV_DEBUG_VALGRIND */ + /* The rest of the block is uninitialized. Silence warnings. */ + MEM_MAKE_DEFINED(b, &block[srv_sort_buf_size] - b); if (!row_merge_write(fd, (*foffs)++, block, crypt_block, space)) { DBUG_RETURN(NULL); } - UNIV_MEM_INVALID(&block[0], srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&block[0], srv_sort_buf_size); +#endif DBUG_RETURN(&block[0]); } @@ -2550,8 +2551,10 @@ write_buffers: break; } - UNIV_MEM_INVALID( +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED( &block[0], srv_sort_buf_size); +#endif /* HAVE_valgrind_or_MSAN */ } } merge_buf[i] = row_merge_buf_empty(buf); @@ -3034,10 +3037,10 @@ row_merge( ulint n_run = 0; /*!< num of runs generated from this merge */ - UNIV_MEM_ASSERT_W(&block[0], 3 * srv_sort_buf_size); + MEM_CHECK_ADDRESSABLE(&block[0], 3 * srv_sort_buf_size); if (crypt_block) { - UNIV_MEM_ASSERT_W(&crypt_block[0], 3 * srv_sort_buf_size); + MEM_CHECK_ADDRESSABLE(&crypt_block[0], 3 * srv_sort_buf_size); } ut_ad(ihalf < file->offset); @@ -3058,7 +3061,9 @@ row_merge( foffs0 = 0; foffs1 = ihalf; - UNIV_MEM_INVALID(run_offset, *num_run * sizeof *run_offset); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(run_offset, *num_run * sizeof *run_offset); +#endif /* HAVE_valgrind_or_MSAN */ for (; foffs0 < ihalf && foffs1 < file->offset; foffs0++, foffs1++) { @@ -3139,7 +3144,9 @@ row_merge( *tmpfd = file->fd; *file = of; - UNIV_MEM_INVALID(&block[0], 3 * srv_sort_buf_size); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&block[0], 3 * srv_sort_buf_size); +#endif /* HAVE_valgrind_or_MSAN */ return(DB_SUCCESS); } @@ -3252,7 +3259,7 @@ row_merge_sort( break; } - UNIV_MEM_ASSERT_RW(run_offset, num_runs * sizeof *run_offset); + MEM_CHECK_DEFINED(run_offset, num_runs * sizeof *run_offset); } while (num_runs > 1); ut_free(run_offset); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 3989095d6c6..b304c03f7ed 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -297,9 +297,7 @@ row_mysql_store_geometry( { /* MySQL might assume the field is set to zero except the length and the pointer fields */ - UNIV_MEM_ASSERT_RW(src, src_len); - UNIV_MEM_ASSERT_W(dest, dest_len); - UNIV_MEM_INVALID(dest, dest_len); + MEM_CHECK_DEFINED(src, src_len); memset(dest, '\0', dest_len); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 15486500b37..9340d5060d9 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -984,9 +984,11 @@ row_sel_get_clust_rec( switch (err) { case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC: - /* Declare the variable uninitialized in Valgrind. +#ifdef HAVE_valgrind_or_MSAN + /* Declare the variable uninitialized. It should be set to DB_SUCCESS at func_exit. */ - UNIV_MEM_INVALID(&err, sizeof err); + MEM_UNDEFINED(&err, sizeof err); +#endif /* HAVE_valgrind_or_MSAN */ break; default: goto err_exit; @@ -2811,9 +2813,11 @@ row_sel_field_store_in_mysql_format_func( #endif /* UNIV_DEBUG */ ut_ad(len != UNIV_SQL_NULL); - UNIV_MEM_ASSERT_RW(data, len); - UNIV_MEM_ASSERT_W(dest, templ->mysql_col_len); - UNIV_MEM_INVALID(dest, templ->mysql_col_len); + MEM_CHECK_DEFINED(data, len); + MEM_CHECK_ADDRESSABLE(dest, templ->mysql_col_len); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(dest, templ->mysql_col_len); +#endif /* HAVE_valgrind_or_MSAN */ switch (templ->type) { const byte* field_end; @@ -3075,9 +3079,9 @@ row_sel_store_mysql_field_func( NULL value is set to the default value. */ ut_ad(templ->mysql_null_bit_mask); - UNIV_MEM_ASSERT_RW(prebuilt->default_rec - + templ->mysql_col_offset, - templ->mysql_col_len); + MEM_CHECK_DEFINED(prebuilt->default_rec + + templ->mysql_col_offset, + templ->mysql_col_len); mysql_rec[templ->mysql_null_byte_offset] |= (byte) templ->mysql_null_bit_mask; memcpy(mysql_rec + templ->mysql_col_offset, @@ -3715,7 +3719,7 @@ row_sel_copy_cached_field_for_mysql( buf += templ->mysql_col_offset; cache += templ->mysql_col_offset; - UNIV_MEM_ASSERT_W(buf, templ->mysql_col_len); + MEM_CHECK_ADDRESSABLE(buf, templ->mysql_col_len); if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR && (templ->type != DATA_INT)) { @@ -3725,7 +3729,9 @@ row_sel_copy_cached_field_for_mysql( row_mysql_read_true_varchar( &len, cache, templ->mysql_length_bytes); len += templ->mysql_length_bytes; - UNIV_MEM_INVALID(buf, templ->mysql_col_len); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(buf, templ->mysql_col_len); +#endif /* HAVE_valgrind_or_MSAN */ } else { len = templ->mysql_col_len; } @@ -3784,7 +3790,7 @@ row_sel_dequeue_cached_row_for_mysql( ut_ad(prebuilt->n_fetch_cached > 0); ut_ad(prebuilt->mysql_prefix_len <= prebuilt->mysql_row_len); - UNIV_MEM_ASSERT_W(buf, prebuilt->mysql_row_len); + MEM_CHECK_ADDRESSABLE(buf, prebuilt->mysql_row_len); cached_rec = prebuilt->fetch_cache[prebuilt->fetch_cache_first]; @@ -3794,7 +3800,9 @@ row_sel_dequeue_cached_row_for_mysql( /* The record is long. Copy it field by field, in case there are some long VARCHAR column of which only a small length is being used. */ - UNIV_MEM_INVALID(buf, prebuilt->mysql_prefix_len); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(buf, prebuilt->mysql_prefix_len); +#endif /* HAVE_valgrind_or_MSAN */ /* First copy the NULL bits. */ ut_memcpy(buf, cached_rec, prebuilt->null_bitmap_len); @@ -3878,8 +3886,10 @@ row_sel_fetch_last_buf( } ut_ad(prebuilt->fetch_cache_first == 0); - UNIV_MEM_INVALID(prebuilt->fetch_cache[prebuilt->n_fetch_cached], - prebuilt->mysql_row_len); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(prebuilt->fetch_cache[prebuilt->n_fetch_cached], + prebuilt->mysql_row_len); +#endif /* HAVE_valgrind_or_MSAN */ return(prebuilt->fetch_cache[prebuilt->n_fetch_cached]); } diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index a7cd06d25fd..63c1ea8d662 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1867,7 +1867,9 @@ row_upd_changes_ord_field_binary_func( /* Silence a compiler warning without silencing a Valgrind error. */ dfield_len = 0; - UNIV_MEM_INVALID(&dfield_len, sizeof dfield_len); +#ifdef HAVE_valgrind_or_MSAN + MEM_UNDEFINED(&dfield_len, sizeof dfield_len); +#endif /* HAVE_valgrind_or_MSAN */ /* See if the column is stored externally. */ buf = row_ext_lookup(ext, col_no, &dfield_len); |