Skip to content

Commit d284940

Browse files
Dmitry ShulgaDmitry Shulga
authored andcommitted
Merge from mysql-5.1 for bug#58026.
2 parents 5ba1fe9 + 6c777a6 commit d284940

6 files changed

Lines changed: 53 additions & 5 deletions

File tree

mysql-test/r/not_embedded_server.result

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ SHOW VARIABLES like 'slave_skip_errors';
33
Variable_name Value
44
slave_skip_errors OFF
55
#
6+
# Bug#58026: massive recursion and crash in regular expression handling
7+
#
8+
SELECT '1' RLIKE RPAD('1', 10000, '(');
9+
#
610
# WL#4284: Transactional DDL locking
711
#
812
# FLUSH PRIVILEGES should not implicitly unlock locked tables.

mysql-test/t/not_embedded_server.test

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@ call mtr.add_suppression("Can't open and lock privilege tables: Table 'host' was
1414

1515
SHOW VARIABLES like 'slave_skip_errors';
1616

17+
--echo #
18+
--echo # Bug#58026: massive recursion and crash in regular expression handling
19+
--echo #
20+
21+
--disable_result_log
22+
--error ER_STACK_OVERRUN_NEED_MORE
23+
SELECT '1' RLIKE RPAD('1', 10000, '(');
24+
--enable_result_log
25+
26+
1727
# End of 5.1 tests
1828

1929
--echo #

regex/my_regex.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef struct {
2828

2929

3030
/* === regcomp.c === */
31+
typedef int (*my_regex_stack_check_t)();
3132
extern int my_regcomp(my_regex_t *, const char *, int, CHARSET_INFO *charset);
3233
#define REG_BASIC 0000
3334
#define REG_EXTENDED 0001
@@ -76,7 +77,8 @@ extern void my_regfree(my_regex_t *);
7677

7778
/* === reginit.c === */
7879

79-
extern void my_regex_init(CHARSET_INFO *cs); /* Should be called for multithread progs */
80+
/* Should be called for multithread progs */
81+
extern void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func);
8082
extern void my_regex_end(void); /* If one wants a clean end */
8183

8284
#ifdef __cplusplus

regex/regcomp.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ struct parse {
3131
CHARSET_INFO *charset; /* for ctype things */
3232
};
3333

34+
/* Check if there is enough stack space for recursion. */
35+
my_regex_stack_check_t my_regex_enough_mem_in_stack= NULL;
36+
3437
#include "regcomp.ih"
3538

3639
static char nuls[10]; /* place to point scanner in event of error */
@@ -117,7 +120,7 @@ CHARSET_INFO *charset;
117120
# define GOODFLAGS(f) ((f)&~REG_DUMP)
118121
#endif
119122

120-
my_regex_init(charset); /* Init cclass if neaded */
123+
my_regex_init(charset, NULL); /* Init cclass if neaded */
121124
preg->charset=charset;
122125
cflags = GOODFLAGS(cflags);
123126
if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
@@ -222,7 +225,15 @@ int stop; /* character this ERE should end at */
222225
/* do a bunch of concatenated expressions */
223226
conc = HERE();
224227
while (MORE() && (c = PEEK()) != '|' && c != stop)
225-
p_ere_exp(p);
228+
{
229+
if (my_regex_enough_mem_in_stack &&
230+
my_regex_enough_mem_in_stack())
231+
{
232+
SETERROR(REG_ESPACE);
233+
return;
234+
}
235+
p_ere_exp(p);
236+
}
226237
if(REQUIRE(HERE() != conc, REG_EMPTY)) {}/* require nonempty */
227238

228239
if (!EAT('|'))

regex/reginit.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
#include <m_ctype.h>
55
#include <m_string.h>
66
#include "cclass.h"
7+
#include "my_regex.h"
78

89
static my_bool regex_inited=0;
10+
extern my_regex_stack_check_t my_regex_enough_mem_in_stack;
911

10-
void my_regex_init(CHARSET_INFO *cs)
12+
void my_regex_init(CHARSET_INFO *cs, my_regex_stack_check_t func)
1113
{
1214
char buff[CCLASS_LAST][256];
1315
int count[CCLASS_LAST];
@@ -16,6 +18,7 @@ void my_regex_init(CHARSET_INFO *cs)
1618
if (!regex_inited)
1719
{
1820
regex_inited=1;
21+
my_regex_enough_mem_in_stack= func;
1922
bzero((uchar*) &count,sizeof(count));
2023

2124
for (i=1 ; i<= 255; i++)
@@ -74,6 +77,7 @@ void my_regex_end()
7477
int i;
7578
for (i=0; i < CCLASS_LAST ; i++)
7679
free((char*) cclasses[i].chars);
80+
my_regex_enough_mem_in_stack= NULL;
7781
regex_inited=0;
7882
}
7983
}

sql/mysqld.cc

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2879,6 +2879,19 @@ sizeof(load_default_groups)/sizeof(load_default_groups[0]);
28792879
#endif
28802880

28812881

2882+
#ifndef EMBEDDED_LIBRARY
2883+
static
2884+
int
2885+
check_enough_stack_size()
2886+
{
2887+
uchar stack_top;
2888+
2889+
return check_stack_overrun(current_thd, STACK_MIN_SIZE,
2890+
&stack_top);
2891+
}
2892+
#endif
2893+
2894+
28822895
/**
28832896
Initialize one of the global date/time format variables.
28842897
@@ -3340,7 +3353,11 @@ static int init_common_variables()
33403353
if (item_create_init())
33413354
return 1;
33423355
item_init();
3343-
my_regex_init(&my_charset_latin1);
3356+
#ifndef EMBEDDED_LIBRARY
3357+
my_regex_init(&my_charset_latin1, check_enough_stack_size);
3358+
#else
3359+
my_regex_init(&my_charset_latin1, NULL);
3360+
#endif
33443361
/*
33453362
Process a comma-separated character set list and choose
33463363
the first available character set. This is mostly for

0 commit comments

Comments
 (0)