1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-40147 MSAN: use-of-uninitialized-value in my_time_compare

Field::get_date and Item::get_date can return true and not
have their ltime pointer structure initialized.

This was the case with Field_vers_trx_id::get_date.

Type_handler_time_common::stored_field_cmp_to_item rather
than doing a my_time_compare on uninitialized values can
return a non-equality (!=0) value for when the fetching of
Field or Item fails and avoid the call to my_time_compare.

Added checks for other invalid results before being
passed to my_time_compare.

Add nonnull as an attribute on my_time_compare and the
unpack_time function it used. Also pack_time since related
and it obviously requires a non-null argument.

Reviewed by: Alexey Midenkov
This commit is contained in:
Daniel Black
2026-06-26 12:30:59 +10:00
parent 113630fdfa
commit ecf1555da7
4 changed files with 54 additions and 8 deletions

View File

@@ -611,3 +611,21 @@ ERROR HY000: Lock wait timeout exceeded; try restarting transaction
disconnect con1;
connection default;
drop table t1;
#
# MDEV-40147 MSAN: use-of-uninitialized-value in my_time_compare
#
create table t (
a int,
row_start bigint unsigned generated always as row start,
row_end bigint unsigned generated always as row end,
period for system_time (row_start, row_end)
) with system versioning engine=InnoDB;
insert into t () values ();
analyze table t persistent for all;
Table Op Msg_type Msg_text
test.t analyze status Engine-independent statistics collected
test.t analyze status OK
select * from t where row_end > current_time();
ERROR HY000: TRX_ID ... not found in `mysql.transaction_registry`
drop table t;
# End of 10.11 tests

View File

@@ -643,3 +643,26 @@ alter table xx;
--disconnect con1
--connection default
drop table t1;
--echo #
--echo # MDEV-40147 MSAN: use-of-uninitialized-value in my_time_compare
--echo #
create table t (
a int,
row_start bigint unsigned generated always as row start,
row_end bigint unsigned generated always as row end,
period for system_time (row_start, row_end)
) with system versioning engine=InnoDB;
insert into t () values ();
analyze table t persistent for all;
--replace_regex /TRX_ID \d+/TRX_ID .../
--error ER_VERS_NO_TRX_ID
select * from t where row_end > current_time();
drop table t;
--echo # End of 10.11 tests

View File

@@ -121,7 +121,8 @@ int append_interval(String *str, interval_type int_type,
*/
bool calc_time_diff(const MYSQL_TIME *l_time1, const MYSQL_TIME *l_time2,
int lsign, MYSQL_TIME *l_time3, date_mode_t fuzzydate);
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b);
int my_time_compare(const MYSQL_TIME *a, const MYSQL_TIME *b)
__attribute__((nonnull));
void localtime_to_TIME(MYSQL_TIME *to, struct tm *from);
void calc_time_from_sec(MYSQL_TIME *to, ulong seconds, ulong microseconds);
@@ -183,8 +184,10 @@ check_date_with_warn(THD *thd, const MYSQL_TIME *ltime,
bool adjust_time_range_with_warn(THD *thd, MYSQL_TIME *ltime, uint dec);
longlong pack_time(const MYSQL_TIME *my_time);
longlong pack_time(const MYSQL_TIME *my_time)
__attribute__((nonnull));
void unpack_time(longlong packed, MYSQL_TIME *my_time,
enum_mysql_timestamp_type ts_type);
enum_mysql_timestamp_type ts_type)
__attribute__((nonnull));
#endif /* SQL_TIME_INCLUDED */

View File

@@ -8951,7 +8951,7 @@ Type_handler_temporal_result::Item_const_eq(const Item_const *a,
{
const MYSQL_TIME *ta= a->const_ptr_mysql_time();
const MYSQL_TIME *tb= b->const_ptr_mysql_time();
return !my_time_compare(ta, tb) &&
return ta && tb && !my_time_compare(ta, tb) &&
(!binary_cmp ||
a->get_type_all_attributes_from_const()->decimals ==
b->get_type_all_attributes_from_const()->decimals);
@@ -9107,8 +9107,9 @@ int Type_handler_temporal_with_date::stored_field_cmp_to_item(THD *thd,
Item *item) const
{
MYSQL_TIME field_time, item_time, item_time2, *item_time_cmp= &item_time;
field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd));
item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd));
if (field->get_date(&field_time, Datetime::Options(TIME_INVALID_DATES, thd))
|| item->get_date(thd, &item_time, Datetime::Options(TIME_INVALID_DATES, thd)))
return -1;
if (item_time.time_type == MYSQL_TIMESTAMP_TIME &&
time_to_datetime(thd, &item_time, item_time_cmp= &item_time2))
return 1;
@@ -9121,8 +9122,9 @@ int Type_handler_time_common::stored_field_cmp_to_item(THD *thd,
Item *item) const
{
MYSQL_TIME field_time, item_time;
field->get_date(&field_time, Time::Options(thd));
item->get_date(thd, &item_time, Time::Options(thd));
if (field->get_date(&field_time, Time::Options(thd))
|| item->get_date(thd, &item_time, Time::Options(thd)))
return -1; /* !=0 is important, and avoid my_time_compare */
return my_time_compare(&field_time, &item_time);
}