LP #1515591: Valgrind error on main.group_min_max

Description

**Reported in Launchpad by Laurynas Biveinis last update 08-08-2016 12:26:43

Valgrind reports an error on main.group_min_max:

main.group_min_max [ fail ] Found warnings/errors in server log file!
Test ended at 2015-11-12 14:04:32
line
==17805== Thread 20:
==17805== Conditional jump or move depends on uninitialised value(s)
==17805== at 0x4C31D52: __memcmp_sse4_1 (vg_replace_strmem.c:1094)
==17805== by 0x9D351E: QUICK_GROUP_MIN_MAX_SELECT::add_range(SEL_ARG*) (opt_range.cc:12888)
==17805== by 0x9D2B2C: TRP_GROUP_MIN_MAX::make_quick(PARAM*, bool, st_mem_root*) (opt_range.cc:12647)
==17805== by 0x9BB882: SQL_SELECT::test_quick_select(THD*, Bitmap<64u>, unsigned long long, unsigned long long, bool, st_order::enum_order) (opt_range.cc:2971)
==17805== by 0xA216F5: get_quick_record_count(THD*, SQL_SELECT*, TABLE*, Bitmap<64u> const*, unsigned long long) (sql_optimizer.cc:4002)
==17805== by 0xA2098B: make_join_statistics(JOIN*, TABLE_LIST*, Item*, Mem_root_array<Key_use, true>*, bool) (sql_optimizer.cc:3713)
==17805== by 0xA17737: JOIN::optimize() (sql_optimizer.cc:382)
==17805== by 0x84A104: mysql_execute_select(THD*, st_select_lex*, bool) (sql_select.cc:1086)
==17805== by 0x84A490: mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, SQL_I_List<st_order>, SQL_I_List<st_order>, Item*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (sql_select.cc:1221)
==17805== by 0x9AA1E2: mysql_explain_unit(THD*, st_select_lex_unit*, select_result*) (opt_explain.cc:2132)
==17805== by 0x9A9DAB: explain_query_expression(THD*, select_result*) (opt_explain.cc:2034)
==17805== by 0x81BD15: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5672)
==17805== by 0x813EAC: mysql_execute_command(THD*) (sql_parse.cc:3010)
==17805== by 0x81EDBD: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:6972)
==17805== by 0x810298: dispatch_command(enum_server_command, THD*, char*, unsigned int) (sql_parse.cc:1442)
==17805== by 0x80F053: do_command(THD*) (sql_parse.cc:1054)
==17805== Uninitialised value was created by a client request
==17805== at 0x9C611A: get_mm_leaf(RANGE_OPT_PARAM*, Item*, Field*, st_key_part*, Item_func::Functype, Item*) (opt_range.cc:7088)
==17805== by 0x9C4C8B: get_mm_parts(RANGE_OPT_PARAM*, Item_func*, Field*, Item_func::Functype, Item*, Item_result) (opt_range.cc:6555)
==17805== by 0x9C3791: get_func_mm_tree(RANGE_OPT_PARAM*, Item_func*, Field*, Item*, Item_result, bool) (opt_range.cc:6119)
==17805== by 0x9C399C: get_full_func_mm_tree(RANGE_OPT_PARAM*, Item_func*, Item_field*, Item*, bool) (opt_range.cc:6219)
==17805== by 0x9C4842: get_mm_tree(RANGE_OPT_PARAM*, Item*) (opt_range.cc:6456)
==17805== by 0x9BB272: SQL_SELECT::test_quick_select(THD*, Bitmap<64u>, unsigned long long, unsigned long long, bool, st_order::enum_order) (opt_range.cc:2830)
==17805== by 0xA216F5: get_quick_record_count(THD*, SQL_SELECT*, TABLE*, Bitmap<64u> const*, unsigned long long) (sql_optimizer.cc:4002)
==17805== by 0xA2098B: make_join_statistics(JOIN*, TABLE_LIST*, Item*, Mem_root_array<Key_use, true>*, bool) (sql_optimizer.cc:3713)
==17805== by 0xA17737: JOIN::optimize() (sql_optimizer.cc:382)
==17805== by 0x84A104: mysql_execute_select(THD*, st_select_lex*, bool) (sql_select.cc:1086)
==17805== by 0x84A490: mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, SQL_I_List<st_order>, SQL_I_List<st_order>, Item*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) (sql_select.cc:1221)
==17805== by 0x9AA1E2: mysql_explain_unit(THD*, st_select_lex_unit*, select_result*) (opt_explain.cc:2132)
==17805== by 0x9A9DAB: explain_query_expression(THD*, select_result*) (opt_explain.cc:2034)
==17805== by 0x81BD15: execute_sqlcom_select(THD*, TABLE_LIST*) (sql_parse.cc:5672)
==17805== by 0x813EAC: mysql_execute_command(THD*) (sql_parse.cc:3010)
==17805== by 0x81EDBD: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:6972)

Environment

None

Smart Checklist

Activity

Show:

lpjirasync January 22, 2018 at 12:33 PM

**Comment from Launchpad by: Laurynas Biveinis on: 08-08-2016 05:51:36

5.5 is now affected too, probably as a result of bug 1588169 fix.

lpjirasync January 22, 2018 at 12:33 PM

**Comment from Launchpad by: Yura Sorokin on: 26-11-2015 16:23:53

Another suspicious "memcmp()" is in the "get_constant_key_infix()" function
*****************************************************************
if (cur_range->maybe_null &&
cur_range->min_value[0] && cur_range->max_value[0])
{
/*
cur_range specifies 'IS NULL'. In this case the argument points
to a "null value" (a copy of is_null_string) that we do not
memcmp(), or memcpy to a field.
*/
DBUG_ASSERT (field_length > 0);
*key_ptr= 1;
key_ptr+= field_length;
*key_infix_len+= field_length;
}
else if (memcmp(cur_range->min_value, cur_range->max_value, field_length) == 0)
{ /* cur_range specifies an equality condition. */
memcpy(key_ptr, cur_range->min_value, field_length);
key_ptr+= field_length;
*key_infix_len+= field_length;
}
else
return false;
*****************************************************************

lpjirasync January 22, 2018 at 12:33 PM

**Comment from Launchpad by: Yura Sorokin on: 26-11-2015 16:05:42

The problem is with "QUICK_GROUP_MIN_MAX_SELECT::add_range()" ("opt_range.cc") which when doing "memcmp()" assumes that both "sel_range->min_value" and "sel_range->max_value" have exactly "min_max_arg_len" significant bytes.
*****************************************************************
if (!(sel_range->min_flag & NO_MIN_RANGE) &&
!(sel_range->max_flag & NO_MAX_RANGE))
{
if (sel_range->maybe_null &&
sel_range->min_value[0] && sel_range->max_value[0])
range_flag|= NULL_RANGE; /* IS NULL condition */
else if (memcmp(sel_range->min_value, sel_range->max_value,
min_max_arg_len) == 0)
range_flag|= EQ_RANGE; /* equality condition */
}
*****************************************************************

However this is not always true.
There are 2 places in "get_mm_leaf()" where "min_value" and "max_value" are not fully initialized (although properly allocated).
1)
*****************************************************************
uchar *null_string=
static_cast<uchar*>(alloc_root(alloc, key_part->store_length + 1));
if (!null_string)
goto end; // out of memory

TRASH(null_string, key_part->store_length + 1);
memcpy(null_string, is_null_string, sizeof(is_null_string));

if (!(tree= new (alloc) SEL_ARG(field, null_string, null_string)))
goto end; // out of memory
*****************************************************************
2)
*****************************************************************
case Item_func::LE_FUNC:
if (!maybe_null)
tree->min_flag=NO_MIN_RANGE; /* From start */
else
{ // > NULL
if (!(tree->min_value=
static_cast<uchar*>(alloc_root(alloc, key_part->store_length+1))))
goto end;
TRASH(tree->min_value, key_part->store_length + 1);
memcpy(tree->min_value, is_null_string, sizeof(is_null_string));
tree->min_flag=NEAR_MIN;
}
break;
*****************************************************************

The fix would be in rewriting "memcmp" logic in "QUICK_GROUP_MIN_MAX_SELECT::add_range()" so that it would perform "memcmp" only when values are not nullable or are nullable and are not currently set to null.

However, it feels safer to zero-set allocated memory (instead of "TRASH()") to make sure that all other similar "memcmp()" calls will produce predictable results.

lpjirasync January 22, 2018 at 12:33 PM

**Comment from Launchpad by: Laurynas Biveinis on: 12-11-2015 12:49:21

May or may not be related to bug 1067099

Done

Details

Assignee

Reporter

Priority

Smart Checklist

Created January 22, 2018 at 12:32 PM
Updated January 22, 2018 at 12:33 PM
Resolved January 22, 2018 at 12:33 PM