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:
Field::set_null(long long) + 0x258 <field.cc : 1644>
1644:=> m_null_ptr[row_offset]|= null_bit;
set_field_to_null_with_conversions(Field*, bool) + 0x128 <field_conv.cc : 190>
190:=> field->set_null();
Item_null::save_in_field_inner(Field*, bool) + 0x15c <item.cc : 6699>
6699:=> return set_field_to_null_with_conversions(field, no_conversions);
Item::save_in_field(Field*, bool) + 0x2bc <item.cc : 6723>
6723:=> const type_conversion_status ret= save_in_field_inner(field, no_conversions);
sp_eval_expr(THD*, Field*, Item**) + 0x7e8 <sp.cc : 2729>
2729:=> expr_item->save_in_field(result_field, false);
sp_rcontext::set_variable(THD*, Field*, Item**) + 0x214 <sp_rcontext.cc : 458>
458:=> return sp_eval_expr(thd, field, value);
sp_rcontext::set_variable(THD*, unsigned int, Item**) + 0x3bc <sp_rcontext.h : 156>
156:=> { return set_variable(thd, m_var_table->field[var_idx], value); }
sp_head::execute_procedure(THD*, List<Item>*) + 0x255c <sp_head.cc : 1433>
1433:=> proc_runtime_ctx->set_variable(thd, i, (Item **)&null_item))
Was allocated at (8192 bytes) [t@25]:
my_raw_malloc() + 0x2a4 <my_malloc.c : 191>
191:=> point= malloc(size);
my_malloc() + 0x1a4 <my_malloc.c : 54>
54:=> mh= (my_memory_header*) my_raw_malloc(raw_size, flags);
alloc_root() + 0xea0 <my_alloc.c : 280>
280:=> get_size,MYF(MY_WME | ME_FATALERROR))))
multi_alloc_root() + 0x650 <my_alloc.c : 344>
344:=> if (!(start= (char*) alloc_root(root, tot_length)))
create_virtual_tmp_table(THD*, List<Create_field>&) + 0x570 <sql_tmp_table.cc : 1958>
1958:=> NullS))
sp_rcontext::init_var_table(THD*) + 0x558 <sp_rcontext.cc : 119>
119:=> if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
sp_rcontext::create(THD*, const sp_pcontext*, Field*) + 0x42c <sp_rcontext.cc : 76>
76:=> ctx->init_var_items(thd))
sp_head::execute_procedure(THD*, List<Item>*) + 0xb48 <sp_head.cc : 1368>
1368:=> parent_sp_runtime_ctx= sp_rcontext::create(thd, m_root_parsing_ctx, NULL);
======================================
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 m_null_ptr[row_offset] operand located
inside inside sql/field.cc set_null() line ~1644
m_null_ptr[row_offset]|= null_bit;
is indeed uninitialized before that point.
Below is 24 lines independent executable t.cc test case which accurately
simulates original issue. For it Discover produces exactly the same UMR
message as for original mysqld server.
t.cc
===================================
#include <stdlib.h>
class Field {
public:
unsigned char null_bit;
void set_null_ptr(unsigned char *p_null_ptr, unsigned p_null_bit) {
m_null_ptr=p_null_ptr;
null_bit=p_null_bit;
}
void set_null(long long row_offset=0);
private: unsigned char *m_null_ptr;
};
void Field::set_null(long long row_offset) {
m_null_ptr[row_offset] |= null_bit;
}
int main() {
unsigned char *ptr;
unsigned bit=1;
Field F;
ptr=(unsigned char*)malloc(8);
F.set_null_ptr(ptr,bit);
F.set_null();
return 0;
}
===================================
Suggested fix:
Somehow initialize 'm_null_ptr[row_offset]' operand before read its valuefrom:
m_null_ptr[row_offset]|= null_bit;