Skip to content

Commit 583868f

Browse files
MDEV-35717: UBSAN: runtime error: applying zero offset to null pointer in my_strnncoll_utf8mb3_general1400_as_ci
Problem: UBSAN reports runtime errors in string comparision functions where pointer arithmetic is done without checking NULL. Fix: Defines a new function `streq_safe` as a replacement for `streq` that resulted in UBSAN errors, capable of handling NULL pointers. Also makes `is_infoschema_db` and `is_perfschema_db` use `streq_safe` for comparision.
1 parent e47db94 commit 583868f

10 files changed

Lines changed: 62 additions & 11 deletions

File tree

mysql-test/main/ctype_utf8mb3_geeral1400_as_ci.result

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,10 @@ DROP TABLE t1;
2323
#
2424
# End of 11.5 tests
2525
#
26+
#
27+
# MDEV-35717: UBSAN: runtime error: applying zero offset to null pointer in `my_strnncoll_utf8mb3_general1400_as_ci`
28+
#
29+
CREATE TABLE t (c INT,c2 CHAR,c3 DATE,CHECK (c>0));
30+
ALTER TABLE t ADD INDEX (c2) USING HASH;
31+
DROP TABLE t;
32+
# End of 11.8 tests

mysql-test/main/ctype_utf8mb3_geeral1400_as_ci.test

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,14 @@ DROP TABLE t1;
2323
--echo #
2424
--echo # End of 11.5 tests
2525
--echo #
26+
27+
--echo #
28+
--echo # MDEV-35717: UBSAN: runtime error: applying zero offset to null pointer in `my_strnncoll_utf8mb3_general1400_as_ci`
29+
--echo #
30+
31+
CREATE TABLE t (c INT,c2 CHAR,c3 DATE,CHECK (c>0));
32+
ALTER TABLE t ADD INDEX (c2) USING HASH;
33+
34+
DROP TABLE t;
35+
36+
--echo # End of 11.8 tests

sql/lex_ident.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,35 @@ class Lex_ident : public Lex_cstring
128128
DBUG_ASSERT(b.is_valid_ident());
129129
return Compare().charset_info()->streq(*this, b);
130130
}
131+
/*
132+
Safe comparison: Returns true if both are NULL, false if one is NULL.
133+
Otherwise calls streq() for a deep character-set comparison.
134+
Treats "NULL identifier" and "empty identifier" as not equal.
135+
136+
Replacement for streq calls that resulted in UBSAN error: applying
137+
zero/non-zero offset to null pointer.
138+
*/
139+
static bool streq_safe(const LEX_CSTRING &a, const LEX_CSTRING &b)
140+
{
141+
if (!a.str || !b.str)
142+
return !a.str && !b.str;
143+
return Lex_ident::streq(a, b);
144+
}
145+
bool streq_safe(const LEX_CSTRING &rhs) const
146+
{
147+
DBUG_ASSERT(is_valid_ident());
148+
if (!str || !rhs.str)
149+
return !str && !rhs.str;
150+
return streq(rhs);
151+
}
152+
bool streq_safe(const Lex_ident &b) const
153+
{
154+
DBUG_ASSERT(is_valid_ident());
155+
DBUG_ASSERT(b.is_valid_ident());
156+
if (!str || !b.str)
157+
return !str && !b.str;
158+
return streq(b);
159+
}
131160
};
132161

133162
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset;

sql/sql_alter.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ uint Alter_info::check_vcol_field(Item_field *item) const
306306
}
307307
for (Create_field &cf: create_list)
308308
{
309-
if (item->field_name.streq(cf.field_name))
309+
if (item->field_name.streq_safe(cf.field_name))
310310
return cf.vcol_info ? cf.vcol_info->flags : 0;
311311
}
312312
return 0;

sql/sql_db.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ static inline bool
100100
cmp_db_names(const Lex_ident_db &db1_name, const Lex_ident_db &db2_name)
101101
{
102102
return (db1_name.length == 0 && db2_name.length == 0) ||
103-
db1_name.streq(db2_name);
103+
db1_name.streq_safe(db2_name);
104104
}
105105

106106
#ifdef HAVE_PSI_INTERFACE

sql/sql_lex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4704,7 +4704,7 @@ struct LEX: public Query_tables_list
47044704

47054705
Table_period_info &info= create_info.period_info;
47064706

4707-
if (check_exists && info.name.streq(name))
4707+
if (check_exists && info.name.streq_safe(name))
47084708
return 0;
47094709

47104710
if (info.is_set())

sql/sql_show.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2586,7 +2586,7 @@ int show_create_table_ex(THD *thd, TABLE_LIST *table_list, const char *force_db,
25862586
{
25872587
Virtual_column_info *check= table->check_constraints[i];
25882588
// period constraint is implicit
2589-
if (share->period.constr_name.streq(check->name))
2589+
if (share->period.constr_name.streq_safe(check->name))
25902590
continue;
25912591

25922592
str.set_buffer_if_not_allocated(&my_charset_utf8mb4_general_ci);

sql/sql_table.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6441,7 +6441,7 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info,
64416441
}
64426442
else if (drop->type == Alter_drop::PERIOD)
64436443
{
6444-
if (table->s->period.name.streq(Lex_ident(drop->name)))
6444+
if (table->s->period.name.streq_safe(Lex_ident(drop->name)))
64456445
remove_drop= FALSE;
64466446
}
64476447
else /* Alter_drop::KEY and Alter_drop::FOREIGN_KEY */
@@ -6752,7 +6752,7 @@ handle_if_exists_options(THD *thd, TABLE *table, Alter_info *alter_info,
67526752
c < share->table_check_constraints ; c++)
67536753
{
67546754
Virtual_column_info *dup= table->check_constraints[c];
6755-
if (check->name.streq(dup->name))
6755+
if (check->name.streq_safe(dup->name))
67566756
{
67576757
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
67586758
ER_DUP_CONSTRAINT_NAME, ER_THD(thd, ER_DUP_CONSTRAINT_NAME),
@@ -9477,7 +9477,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table,
94779477
}
94789478
}
94799479

9480-
if (share->period.constr_name.streq(check->name))
9480+
if (share->period.constr_name.streq_safe(check->name))
94819481
{
94829482
if (!drop_period && !keep)
94839483
{

sql/table.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3618,12 +3618,12 @@ extern Lex_ident_table MYSQL_PROC_NAME;
36183618

36193619
inline bool is_infoschema_db(const LEX_CSTRING *name)
36203620
{
3621-
return INFORMATION_SCHEMA_NAME.streq(*name);
3621+
return name->str && name->length && INFORMATION_SCHEMA_NAME.streq_safe(*name);
36223622
}
36233623

36243624
inline bool is_perfschema_db(const LEX_CSTRING *name)
36253625
{
3626-
return PERFORMANCE_SCHEMA_DB_NAME.streq(*name);
3626+
return name->str && name->length && PERFORMANCE_SCHEMA_DB_NAME.streq_safe(*name);
36273627
}
36283628

36293629
inline void mark_as_null_row(TABLE *table)

strings/strcoll.inl

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,12 @@ MY_FUNCTION_NAME(strnncoll)(CHARSET_INFO *cs __attribute__((unused)),
226226
const uchar *b, size_t b_length,
227227
my_bool b_is_prefix)
228228
{
229-
const uchar *a_end= a + a_length;
230-
const uchar *b_end= b + b_length;
229+
const uchar *a_end, *b_end;
230+
DBUG_ASSERT(a);
231+
DBUG_ASSERT(b);
232+
233+
a_end= a + a_length;
234+
b_end= b + b_length;
231235
for ( ; ; )
232236
{
233237
int a_weight, b_weight, res;

0 commit comments

Comments
 (0)