Commit af784385 authored by Monty's avatar Monty

Fix for using uninitialized memory

MDEV-22073 MSAN use-of-uninitialized-value in
collect_statistics_for_table()

Other things:
innodb.analyze_table was changed to mainly test statistic
collection. Was discussed with Marko.
parent 277aa85c
......@@ -33,6 +33,7 @@
#if defined(HAVE_VALGRIND_MEMCHECK_H) && defined(HAVE_valgrind)
# include <valgrind/memcheck.h>
# define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len)
# define MEM_MAKE_DEFINED(a,len) VALGRIND_MAKE_MEM_DEFINED(a,len)
# define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len)
# define MEM_CHECK_ADDRESSABLE(a,len) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,len)
# define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len)
......@@ -42,12 +43,22 @@
/* How to do manual poisoning:
https://github.com/google/sanitizers/wiki/AddressSanitizerManualPoisoning */
# define MEM_UNDEFINED(a,len) ASAN_UNPOISON_MEMORY_REGION(a,len)
# define MEM_MAKE_DEFINED(a,len) ((void) 0)
# define MEM_NOACCESS(a,len) ASAN_POISON_MEMORY_REGION(a,len)
# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0)
# define MEM_CHECK_DEFINED(a,len) ((void) 0)
# define REDZONE_SIZE 8
#elif __has_feature(memory_sanitizer)
# include <sanitizer/msan_interface.h>
# define MEM_UNDEFINED(a,len) __msan_allocated_memory(a,len)
# define MEM_MAKE_DEFINED(a,len) __msan_unpoison(a,len)
# define MEM_NOACCESS(a,len) ((void) 0)
# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0)
# define MEM_CHECK_DEFINED(a,len) __msan_check_mem_is_initialized(a,len)
# define REDZONE_SIZE 8
#else
# define MEM_UNDEFINED(a,len) ((void) (a), (void) (len))
# define MEM_MAKE_DEFINED(a,len) ((void) 0)
# define MEM_NOACCESS(a,len) ((void) 0)
# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0)
# define MEM_CHECK_DEFINED(a,len) ((void) 0)
......@@ -55,12 +66,15 @@
#endif /* HAVE_VALGRIND_MEMCHECK_H */
#ifndef DBUG_OFF
/* NOTE: Do not invoke TRASH_FILL directly! Use TRASH_ALLOC or TRASH_FREE.
The MEM_UNDEFINED() call before memset() is for canceling the effect
of any previous MEM_NOACCESS(). We must invoke MEM_UNDEFINED() after
writing the dummy pattern, unless MEM_NOACCESS() is going to be invoked.
On AddressSanitizer, the MEM_UNDEFINED() in TRASH_ALLOC() has no effect. */
/*
TRASH_FILL() has to call MEM_UNDEFINED() to cancel any effect of TRASH_FREE().
This can happen in the case one does
TRASH_ALLOC(A,B) ; TRASH_FREE(A,B) ; TRASH_ALLOC(A,B)
to reuse the same memory in an internal memory allocator like MEM_ROOT.
For my_malloc() and safemalloc() the extra MEM_UNDEFINED is bit of an
overkill.
TRASH_FILL() is an internal function and should not be used externally.
*/
#define TRASH_FILL(A,B,C) do { const size_t trash_tmp= (B); MEM_UNDEFINED(A, trash_tmp); memset(A, C, trash_tmp); } while (0)
#else
#define TRASH_FILL(A,B,C) do { MEM_UNDEFINED((A), (B)); } while (0)
......
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i int DEFAULT 1;
START TRANSACTION;
WHILE (i <= 1000000) DO
INSERT INTO t1 VALUES (i, i, CONCAT('a', i));
SET i = i + 1;
END WHILE;
COMMIT;
END|
set use_stat_tables='preferably';
CREATE TABLE t1(
class INT,
id INT,
title VARCHAR(100)
) ENGINE=InnoDB;
insert into t1 select seq, seq, concat('a', seq) from seq_1_to_500;
SELECT COUNT(*) FROM t1;
COUNT(*)
1000000
SET GLOBAL innodb_stats_persistent_sample_pages=2000;
500
set @@max_heap_table_size=16384;
ANALYZE TABLE t1;
Table Op Msg_type Msg_text
test.t1 analyze status Engine-independent statistics collected
test.t1 analyze status OK
DROP TABLE t1;
DROP PROCEDURE populate_t1;
SET GLOBAL innodb_stats_persistent_sample_pages=default;
#
# BUG#22385442 - INNODB: DIFFICULT TO FIND FREE BLOCKS IN THE BUFFER POOL
#
--source include/have_innodb.inc
--source include/big_test.inc
--source include/have_sequence.inc
DELIMITER |;
CREATE PROCEDURE populate_t1()
BEGIN
DECLARE i int DEFAULT 1;
#
# MDEV-22073 MSAN use-of-uninitialized-value in collect_statistics_for_table()
#
START TRANSACTION;
WHILE (i <= 1000000) DO
INSERT INTO t1 VALUES (i, i, CONCAT('a', i));
SET i = i + 1;
END WHILE;
COMMIT;
END|
DELIMITER ;|
set use_stat_tables='preferably';
CREATE TABLE t1(
class INT,
......@@ -25,18 +13,11 @@ CREATE TABLE t1(
title VARCHAR(100)
) ENGINE=InnoDB;
-- disable_query_log
CALL populate_t1();
-- enable_query_log
insert into t1 select seq, seq, concat('a', seq) from seq_1_to_500;
SELECT COUNT(*) FROM t1;
SET GLOBAL innodb_stats_persistent_sample_pages=2000;
set @@max_heap_table_size=16384;
ANALYZE TABLE t1;
DROP TABLE t1;
DROP PROCEDURE populate_t1;
SET GLOBAL innodb_stats_persistent_sample_pages=default;
......@@ -7772,6 +7772,12 @@ my_decimal *Field_varstring::val_decimal(my_decimal *decimal_value)
}
void Field_varstring::mark_unused_memory_as_defined()
{
uint used_length __attribute__((unused)) = get_length();
MEM_MAKE_DEFINED(get_data() + used_length, field_length - used_length);
}
int Field_varstring::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
uint max_len)
......
......@@ -850,6 +850,14 @@ class Field: public Value_source
enum_check_fields check_level);
int store(const LEX_STRING *ls, CHARSET_INFO *cs)
{ return store(ls->str, (uint32) ls->length, cs); }
/*
Mark unused memory in the field as defined. Mainly used to ensure
that if we write full field to disk (for example in
Count_distinct_field::add(), we don't write unitalized data to
disk which would confuse valgrind or MSAN.
*/
virtual void mark_unused_memory_as_defined() {}
virtual double val_real(void)=0;
virtual longlong val_int(void)=0;
/*
......@@ -3242,6 +3250,7 @@ class Field_varstring :public Field_longstr {
int store(const char *to,uint length,CHARSET_INFO *charset);
int store(longlong nr, bool unsigned_val);
int store(double nr) { return Field_str::store(nr); } /* QQ: To be deleted */
void mark_unused_memory_as_defined();
double val_real(void);
longlong val_int(void);
String *val_str(String*,String *);
......
......@@ -1671,6 +1671,7 @@ class Count_distinct_field: public Sql_alloc
*/
virtual bool add()
{
table_field->mark_unused_memory_as_defined();
return tree->unique_add(table_field->ptr);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment