Description:
Oracle's tool called Discover detects UMR (Uninitialized Memory Read)
in mysqld server when executing '1st' test case located inside
MySQL 5.7.10. This UMR was produced on Sparc Solaris 11.3 T7 system,
but it's not platform specific, and can occur on any other platform.
Error message and call stack reported by Discover looks like this:
======================================
(UMR): accessing uninitialized data ... (1 byte) on the heap:
mach_read_from_1(const unsigned char*) + 0xec <mach0data.ic : 75>
75:=> return((ulint)(b[0]));
rec_set_bit_field_1(unsigned char*, ... <rem0rec.ic : 192>
192:=> | (val << shift));
rec_set_status(unsigned char*, unsigned long) + 0xc8 <rem0rec.ic : 657>
657:=> REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT);
rec_set_info_and_status_bits(unsigned char*, unsigned long) + 0xc0 <rem0rec.ic : 698>
698:=> rec_set_status(rec, bits & REC_NEW_STATUS_MASK);
rec_convert_dtuple_to_rec_new(unsigned char*,... <rem0rec.cc : 1443>
1443:=> rec_set_info_and_status_bits(rec, dtuple_get_info_bits(dtuple));
rec_convert_dtuple_to_rec(unsigned char*, ... <rem0rec.cc : 1471>
1471:=> rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
page_cur_tuple_insert(page_cur_t*, ... <page0cur.ic : 271>
271:=> index, tuple, n_ext);
btr_root_raise_and_insert(unsigned long, ... <btr0btr.cc : 1749>
1749:=> index, offsets, heap, 0, mtr);
Was allocated at (1160 bytes) [t@25]:
ut_allocator<unsigned char>::allocate(unsigned long, ... <ut0new.h : 351>
351:=> ptr = malloc(total_bytes);
mem_heap_create_block_func(mem_block_info_t*, ... <mem0mem.cc : 302>
302:=> block = static_cast<mem_block_t*>(ut_malloc_nokey(len));
mem_heap_create_func(unsigned long, ... <mem0mem.ic : 493>
493:=> block = mem_heap_create_block(NULL, size, type, file_name, line);
btr_root_raise_and_insert(unsigned long, ... <btr0btr.cc : 1706>
1706:=> *heap = mem_heap_create(1000);
btr_cur_pessimistic_insert(unsigned long, ... <btr0cur.cc : 3459>
3459:=> flags, cursor, offsets, heap, entry, n_ext, mtr);
row_ins_sorted_clust_index_entry(unsigned long, ... <row0ins.cc : 2609>
2609:=> thr, mtr);
row_ins_clust_index_entry(dict_index_t*, ... <row0ins.cc : 3184>
3184:=> BTR_MODIFY_TREE, index, entry, n_ext, thr);
row_insert_for_mysql_using_cursor(const unsigned char*, <row0mysql.cc : 1590>
1590:=> node->index, node->entry, thr, 0, false);
======================================
How to repeat:
1. If you have access to Discover tool, and latest Sun Studio C/C++ compilers
you need to build MySQL-5.7.10 sources in debug mode on Solaris Sparc,
then launch discover binary with input argument as mysqld binary,
and when completed to take a look inside mysql.html file which should
contain call stack shown in description above.
2. If you do not have access to Discover, you need to debug MySQL server
with '1st' test case, and to see that b[0] argument located
inside inside storage/innobase/include/mach0data.ic mach_read_from_1() line ~75
return((ulint)(b[0]));
is indeed uninitialized before that point.
Below is 33 lines independent executable t.c test case which accurately
simulates original issue. For it Discover produces exactly the same UMR
message as for original mysqld server.
t.c
===================================
#include <stdlib.h>
typedef unsigned char byte;
typedef byte rec_t;
typedef unsigned long int ulint;
ulint mach_read_from_1(const byte*b){
return ((ulint)(b[0]));
}
void rec_set_bit_field_1(rec_t* rec, ulint offs) {
mach_read_from_1(rec-offs);
}
void rec_set_status( rec_t* rec, ulint bits) {
rec_set_bit_field_1(rec, bits);
}
void rec_set_info_and_status_bits( rec_t* rec,ulint bits) {
rec_set_status(rec, bits & 7);
}
static rec_t* rec_convert_dtuple_to_rec_new(byte *buf) {
ulint extra_size=6;
rec_t* rec;
rec = buf+extra_size;
rec_set_info_and_status_bits(rec,17);
}
rec_t* rec_convert_dtuple_to_rec(byte* buf) {
rec_t* rec;
rec=rec_convert_dtuple_to_rec_new(buf);
return rec;
}
int main () {
rec_convert_dtuple_to_rec((byte*)malloc(16));
return 0;
}
===================================
Suggested fix:
Somehow initialize 'b[0]' argument before passes its value into return ((ulint)(b[0]));