From 8f452530e61b299d4d48f82f41ab5364723607ae Mon Sep 17 00:00:00 2001 From: Rickard Green Date: Wed, 5 Apr 2017 14:32:16 +0200 Subject: Stack guard for PCRE --- erts/emulator/beam/beam_debug.c | 46 ++++++++++++++++++++++++ erts/emulator/beam/erl_bif_info.c | 15 ++++++++ erts/emulator/beam/erl_bif_re.c | 35 ++++++++++++++++++ erts/emulator/beam/erl_init.c | 52 +++++++++++++++++++-------- erts/emulator/beam/global.h | 15 ++++++++ erts/emulator/beam/sys.h | 2 ++ erts/emulator/beam/utils.c | 47 ++++++++++++++++++++++++ erts/emulator/pcre/local_config.h | 2 +- erts/emulator/sys/unix/sys.c | 12 +++++++ erts/emulator/sys/win32/sys.c | 6 ++++ erts/emulator/test/erts_debug_SUITE.erl | 14 ++++++-- erts/include/internal/ethr_internal.h | 1 + erts/include/internal/ethread.h | 3 ++ erts/lib_src/common/ethr_aux.c | 64 +++++++++++++++++++++++++++++++-- erts/lib_src/pthread/ethread.c | 25 +++++++++---- erts/lib_src/win/ethread.c | 21 +++++++---- lib/stdlib/test/re_SUITE.erl | 12 +++++-- 17 files changed, 334 insertions(+), 38 deletions(-) diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c index 21d336049f..d708cf89a7 100644 --- a/erts/emulator/beam/beam_debug.c +++ b/erts/emulator/beam/beam_debug.c @@ -731,3 +731,49 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr) return size; } + + +#ifdef ERTS_SMP +# define ERTS_STACK_LIMIT ((char *) ethr_get_stacklimit()) +#else +# define ERTS_STACK_LIMIT ((char *) erts_scheduler_stack_limit) +#endif + +/* + * The below functions is for testing of the stack + * limit functionality. They are intentionally + * written body recursive in order to prevent + * last call optimization... + */ + +UWord +erts_check_stack_recursion_downwards(char *start_c) +{ + char *limit = ERTS_STACK_LIMIT; + char c; + UWord res; + if (erts_check_below_limit(&c, limit + 1024)) + return (char *) erts_ptr_id(start_c) - (char *) erts_ptr_id(&c); + res = erts_check_stack_recursion_downwards(start_c); + erts_ptr_id(&c); + return res; +} + +UWord +erts_check_stack_recursion_upwards(char *start_c) +{ + char *limit = ERTS_STACK_LIMIT; + char c; + UWord res; + if (erts_check_above_limit(&c, limit - 1024)) + return (char *) erts_ptr_id(&c) - (char *) erts_ptr_id(start_c); + res = erts_check_stack_recursion_upwards(start_c); + erts_ptr_id(&c); + return res; +} + +int +erts_is_above_stack_limit(char *ptr) +{ + return (char *) ptr > ERTS_STACK_LIMIT; +} diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 7bd45916f5..dd1299ca57 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -3674,6 +3674,21 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1) BIF_RET(erts_sint64_to_big(value, &hp)); } } + else if (ERTS_IS_ATOM_STR("stack_check", BIF_ARG_1)) { + UWord size; + char c; + if (erts_is_above_stack_limit(&c)) + size = erts_check_stack_recursion_downwards(&c); + else + size = erts_check_stack_recursion_upwards(&c); + if (IS_SSMALL(size)) + BIF_RET(make_small(size)); + else { + Uint hsz = BIG_UWORD_HEAP_SIZE(size); + Eterm *hp = HAlloc(BIF_P, hsz); + BIF_RET(uword_to_big(size, hp)); + } + } } else if (is_tuple(BIF_ARG_1)) { Eterm* tp = tuple_val(BIF_ARG_1); diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c index ff7746ce1d..35b196743f 100644 --- a/erts/emulator/beam/erl_bif_re.c +++ b/erts/emulator/beam/erl_bif_re.c @@ -64,12 +64,47 @@ static void erts_erts_pcre_stack_free(void *ptr) { erts_free(ERTS_ALC_T_RE_STACK,ptr); } +#define ERTS_PCRE_STACK_MARGIN (10*1024) + +#ifdef ERTS_SMP +# define ERTS_STACK_LIMIT ((char *) ethr_get_stacklimit()) +#else +# define ERTS_STACK_LIMIT ((char *) erts_scheduler_stack_limit) +#endif + +static int +stack_guard_downwards(void) +{ + char *limit = ERTS_STACK_LIMIT; + char c; + + ASSERT(limit); + + return erts_check_below_limit(&c, limit + ERTS_PCRE_STACK_MARGIN); +} + +static int +stack_guard_upwards(void) +{ + char *limit = ERTS_STACK_LIMIT; + char c; + + ASSERT(limit); + + return erts_check_above_limit(&c, limit - ERTS_PCRE_STACK_MARGIN); +} + void erts_init_bif_re(void) { + char c; erts_pcre_malloc = &erts_erts_pcre_malloc; erts_pcre_free = &erts_erts_pcre_free; erts_pcre_stack_malloc = &erts_erts_pcre_stack_malloc; erts_pcre_stack_free = &erts_erts_pcre_stack_free; + if ((char *) erts_ptr_id(&c) > ERTS_STACK_LIMIT) + erts_pcre_stack_guard = stack_guard_downwards; + else + erts_pcre_stack_guard = stack_guard_upwards; default_table = NULL; /* ISO8859-1 default, forced into pcre */ max_loop_limit = CONTEXT_REDS * LOOP_FACTOR; diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index e8b8739852..4e408e8305 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -61,6 +61,9 @@ #define ERTS_DEFAULT_NO_ASYNC_THREADS 10 +#define ERTS_DEFAULT_SCHED_STACK_SIZE 256 +#define ERTS_MIN_SCHED_STACK_SIZE 20 + /* * The variables below (prefixed with etp_) are for erts/etc/unix/etp-commands * only. Do not remove even though they aren't used elsewhere in the emulator! @@ -123,6 +126,8 @@ const Eterm etp_hole_marker = ERTS_HOLE_MARKER; const Eterm etp_hole_marker = 0; #endif +static int modified_sched_thread_suggested_stack_size = 0; + /* * Note about VxWorks: All variables must be initialized by executable code, * not by an initializer. Otherwise a new instance of the emulator will @@ -1231,24 +1236,38 @@ early_init(int *argc, char **argv) /* } #ifndef ERTS_SMP + +void *erts_scheduler_stack_limit; + + static void set_main_stack_size(void) { - if (erts_sched_thread_suggested_stack_size > 0) { + char c; + UWord stacksize; # if HAVE_DECL_GETRLIMIT && HAVE_DECL_SETRLIMIT && HAVE_DECL_RLIMIT_STACK - struct rlimit rl; - int bytes = erts_sched_thread_suggested_stack_size * sizeof(Uint) * 1024; - if (getrlimit(RLIMIT_STACK, &rl) != 0 || - (rl.rlim_cur = bytes, setrlimit(RLIMIT_STACK, &rl) != 0)) { - erts_fprintf(stderr, "failed to set stack size for scheduler " - "thread to %d bytes\n", bytes); - erts_usage(); - } + struct rlimit rl; + int bytes; + stacksize = erts_sched_thread_suggested_stack_size * sizeof(Uint) * 1024; + /* Add some extra pages... neede by some systems... */ + bytes = (int) stacksize + 3*erts_sys_get_page_size(); + if (getrlimit(RLIMIT_STACK, &rl) != 0 || + (rl.rlim_cur = bytes, setrlimit(RLIMIT_STACK, &rl) != 0)) { + erts_fprintf(stderr, "failed to set stack size for scheduler " + "thread to %d bytes\n", bytes); + erts_usage(); + } # else + if (modified_sched_thread_suggested_stack_size) { erts_fprintf(stderr, "no OS support for dynamic stack size limit\n"); - erts_usage(); -# endif + erts_usage(); } + /* Be conservative and hope it is not more than 64 kWords... */ + stacksize = 64*1024*sizeof(void *); +# endif + + erts_scheduler_stack_limit = erts_calc_stacklimit(&c, stacksize); } + #endif void @@ -1293,12 +1312,11 @@ erl_start(int argc, char **argv) port_tab_sz_ignore_files = 1; } -#if (defined(__APPLE__) && defined(__MACH__)) || defined(__DARWIN__) /* - * The default stack size on MacOS X is too small for pcre. + * A default stack size suitable for pcre which might use quite + * a lot of stack. */ - erts_sched_thread_suggested_stack_size = 256; -#endif + erts_sched_thread_suggested_stack_size = ERTS_DEFAULT_SCHED_STACK_SIZE; #ifdef DEBUG verbose = DEBUG_DEFAULT; @@ -1921,6 +1939,7 @@ erl_start(int argc, char **argv) /* suggested stack size (Kilo Words) for scheduler threads */ arg = get_arg(sub_param+2, argv[i+1], &i); erts_sched_thread_suggested_stack_size = atoi(arg); + modified_sched_thread_suggested_stack_size = 1; if ((erts_sched_thread_suggested_stack_size < ERTS_SCHED_THREAD_MIN_STACK_SIZE) @@ -2230,6 +2249,9 @@ erl_start(int argc, char **argv) boot_argc = argc - i; /* Number of arguments to init */ boot_argv = &argv[i]; + if (erts_sched_thread_suggested_stack_size < ERTS_MIN_SCHED_STACK_SIZE) + erts_sched_thread_suggested_stack_size = ERTS_MIN_SCHED_STACK_SIZE; + erl_init(ncpu, proc_tab_sz, legacy_proc_tab, diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 19286e1310..45c01673d8 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1218,6 +1218,11 @@ void erts_short_init(void); void erl_start(int, char**); void erts_usage(void); Eterm erts_preloaded(Process* p); + +#ifndef ERTS_SMP +extern void *erts_scheduler_stack_limit; +#endif + /* erl_md5.c */ typedef struct { @@ -1278,6 +1283,11 @@ Uint64 erts_timestamp_millis(void); Export* erts_find_function(Eterm, Eterm, unsigned int, ErtsCodeIndex); +void *erts_calc_stacklimit(char *prev_c, UWord stacksize); +int erts_check_below_limit(char *ptr, char *limit); +int erts_check_above_limit(char *ptr, char *limit); +void *erts_ptr_id(void *ptr); + Eterm store_external_or_ref_in_proc_(Process *, Eterm); Eterm store_external_or_ref_(Uint **, ErlOffHeap*, Eterm); @@ -1313,6 +1323,11 @@ void erts_init_external(void); /* erl_map.c */ void erts_init_map(void); +/* beam_debug.c */ +UWord erts_check_stack_recursion_downwards(char *start_c); +UWord erts_check_stack_recursion_upwards(char *start_c); +int erts_is_above_stack_limit(char *ptr); + /* erl_unicode.c */ void erts_init_unicode(void); Sint erts_unicode_set_loop_limit(Sint limit); diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index d49edad6dc..41ba51d037 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -604,6 +604,8 @@ __decl_noreturn void __noreturn erts_exit(int n, char*, ...); Eterm erts_check_io_info(void *p); +UWord erts_sys_get_page_size(void); + /* Size of misc memory allocated from system dependent code */ Uint erts_sys_misc_mem_sz(void); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index d90c282c7e..d91ae1ffe6 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -5031,6 +5031,53 @@ Uint64 erts_timestamp_millis(void) #endif } +void * +erts_calc_stacklimit(char *prev_c, UWord stacksize) +{ + /* + * We *don't* want this function inlined, i.e., it is + * risky to call this function from another function + * in utils.c + */ + + UWord pagesize = erts_sys_get_page_size(); + char c; + char *start; + if (&c > prev_c) { + start = (char *) ((((UWord) prev_c) / pagesize) * pagesize); + return (void *) (start + stacksize); + } + else { + start = (char *) (((((UWord) prev_c) - 1) / pagesize + 1) * pagesize); + return (void *) (start - stacksize); + } +} + +/* + * erts_check_below_limit() and + * erts_check_above_limit() are put + * in utils.c in order to prevent + * inlining. + */ + +int +erts_check_below_limit(char *ptr, char *limit) +{ + return ptr < limit; +} + +int +erts_check_above_limit(char *ptr, char *limit) +{ + return ptr > limit; +} + +void * +erts_ptr_id(void *ptr) +{ + return ptr; +} + #ifdef DEBUG /* * Handy functions when using a debugger - don't use in the code! diff --git a/erts/emulator/pcre/local_config.h b/erts/emulator/pcre/local_config.h index 6a0b7b4d4d..e90f4dcada 100644 --- a/erts/emulator/pcre/local_config.h +++ b/erts/emulator/pcre/local_config.h @@ -58,7 +58,7 @@ /* The value of PARENS_NEST_LIMIT specifies the maximum depth of nested parentheses (of any kind) in a pattern. This limits the amount of system stack that is used while compiling a pattern. */ -#define PARENS_NEST_LIMIT 250 +#define PARENS_NEST_LIMIT 10000 /* Define if linking statically (TODO: make nice with Libtool) */ #define PCRE_STATIC 1 diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 6459fa064b..0c0acbf90c 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -275,6 +275,18 @@ erts_sys_schedule_interrupt_timed(int set, ErtsMonotonicTime timeout_time) } #endif +UWord +erts_sys_get_page_size(void) +{ +#if defined(_SC_PAGESIZE) + return (UWord) sysconf(_SC_PAGESIZE); +#elif defined(HAVE_GETPAGESIZE) + return (UWord) getpagesize(); +#else + return (UWord) 4*1024; /* Guess 4 KB */ +#endif +} + Uint erts_sys_misc_mem_sz(void) { diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index f3881e0736..2cd88b503e 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -186,6 +186,12 @@ void sys_primitive_init(HMODULE beam) beam_module = (HMODULE) beam; } +UWord +erts_sys_get_page_size(void) +{ + return (UWord) 4*1024; /* Guess 4 KB */ +} + Uint erts_sys_misc_mem_sz(void) { diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl index 23871585f7..c9c664de38 100644 --- a/erts/emulator/test/erts_debug_SUITE.erl +++ b/erts/emulator/test/erts_debug_SUITE.erl @@ -23,14 +23,15 @@ -export([all/0, suite/0, test_size/1,flat_size_big/1,df/1,term_type/1, - instructions/1]). + instructions/1, stack_check/1]). suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 2}}]. all() -> - [test_size, flat_size_big, df, instructions, term_type]. + [test_size, flat_size_big, df, instructions, term_type, + stack_check]. test_size(Config) when is_list(Config) -> ConsCell1 = id([a|b]), @@ -181,6 +182,15 @@ df(Config) when is_list(Config) -> true = (P0 == pps()), ok. +stack_check(Config) when is_list(Config) -> + erts_debug:set_internal_state(available_internal_state,true), + %% Recurses on the C stack until stacklimit is reached. That + %% is, tests that the stack limit functionality works (used + %% by PCRE). VM will crash if it doesn't work... + Size = erts_debug:get_internal_state(stack_check), + erts_debug:set_internal_state(available_internal_state,false), + {comment, "Stack size: "++integer_to_list(Size)++" bytes"}. + df_smoke([M|Ms]) -> io:format("~p", [M]), erts_debug:df(M), diff --git a/erts/include/internal/ethr_internal.h b/erts/include/internal/ethr_internal.h index 6657c8affc..d42d93afc6 100644 --- a/erts/include/internal/ethr_internal.h +++ b/erts/include/internal/ethr_internal.h @@ -90,6 +90,7 @@ int ethr_init_common__(ethr_init_data *id); int ethr_late_init_common__(ethr_late_init_data *lid); void ethr_run_exit_handlers__(void); void ethr_ts_event_destructor__(void *vtsep); +void ethr_set_stacklimit__(char *prev_c, size_t stacksize); #if defined(ETHR_X86_RUNTIME_CONF__) void ethr_x86_cpuid__(int *eax, int *ebx, int *ecx, int *edx); diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index b23644d361..9f23bd09c4 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -516,6 +516,9 @@ int ethr_tsd_key_delete(ethr_tsd_key); int ethr_tsd_set(ethr_tsd_key, void *); void *ethr_tsd_get(ethr_tsd_key); +void *ethr_get_stacklimit(void); +int ethr_set_stacklimit(void *limit); + #ifdef ETHR_HAVE_ETHR_SIG_FUNCS #include int ethr_sigmask(int how, const sigset_t *set, sigset_t *oset); diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c index 3501fe335a..bbffca4d6d 100644 --- a/erts/lib_src/common/ethr_aux.c +++ b/erts/lib_src/common/ethr_aux.c @@ -68,6 +68,8 @@ size_t ethr_max_stack_size__; /* kilo words */ ethr_rwmutex xhndl_rwmtx; ethr_xhndl_list *xhndl_list; +static ethr_tsd_key ethr_stacklimit_key__; + static int main_threads; static int init_ts_event_alloc(void); @@ -237,13 +239,11 @@ ethr_init_common__(ethr_init_data *id) #endif ethr_min_stack_size__ = ETHR_PAGE_ALIGN(ethr_min_stack_size__); - ethr_min_stack_size__ = ETHR_B2KW(ethr_min_stack_size__); - ethr_max_stack_size__ = 32*1024*1024; #if SIZEOF_VOID_P == 8 ethr_max_stack_size__ *= 2; #endif - ethr_max_stack_size__ = ETHR_B2KW(ethr_max_stack_size__); + ethr_max_stack_size__ = ETHR_PAGE_ALIGN(ethr_max_stack_size__); res = ethr_init_atomics(); if (res != 0) @@ -253,6 +253,10 @@ ethr_init_common__(ethr_init_data *id) if (res != 0) return res; + res = ethr_tsd_key_create(ðr_stacklimit_key__, "stacklimit"); + if (res != 0) + return res; + xhndl_list = NULL; return 0; @@ -313,6 +317,60 @@ ethr_late_init_common__(ethr_late_init_data *lid) return 0; } +/* + * Stack limit + */ + +void *ethr_get_stacklimit(void) +{ + return ethr_tsd_get(ethr_stacklimit_key__); +} + +int ethr_set_stacklimit(void *limit) +{ + void *prev = ethr_tsd_get(ethr_stacklimit_key__); + if (prev) + return EACCES; + if (!limit) + return EINVAL; + return ethr_tsd_set(ethr_stacklimit_key__, limit); +} + +/* internal stacklimit (thread creation) */ + +void +ethr_set_stacklimit__(char *prev_c, size_t stacksize) +{ + /* + * We *don't* want this function inlined, i.e., it is + * risky to call this function from another function + * in ethr_aux.c + */ + void *limit = NULL; + char c; + int res; + + if (stacksize) { + char *start; + if (&c > prev_c) { + start = (char *) ((((ethr_uint_t) prev_c) + / ethr_pagesize__) + * ethr_pagesize__); + limit = start + stacksize; + } + else { + start = (char *) (((((ethr_uint_t) prev_c) - 1) + / ethr_pagesize__ + 1) + * ethr_pagesize__); + limit = start - stacksize; + } + } + + res = ethr_tsd_set(ethr_stacklimit_key__, limit); + if (res != 0) + ethr_abort__(); +} + int ethr_install_exit_handler(void (*funcp)(void)) { diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index 29bffa7e12..f0d4296445 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -81,6 +81,7 @@ typedef struct { void *(*thr_func)(void *); void *arg; void *prep_func_res; + size_t stacksize; char *name; char name_buff[16]; } ethr_thr_wrap_data__; @@ -88,12 +89,15 @@ typedef struct { static void *thr_wrapper(void *vtwd) { ethr_sint32_t result; + char c; void *res; ethr_thr_wrap_data__ *twd = (ethr_thr_wrap_data__ *) vtwd; void *(*thr_func)(void *) = twd->thr_func; void *arg = twd->arg; ethr_ts_event *tsep = NULL; + ethr_set_stacklimit__(&c, twd->stacksize); + result = (ethr_sint32_t) ethr_make_ts_event__(&tsep); if (result == 0) { @@ -330,6 +334,7 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, twd.tse = ethr_get_ts_event(); twd.thr_func = func; twd.arg = arg; + twd.stacksize = 0; if (opts && opts->name) { snprintf(twd.name_buff, 16, "%s", opts->name); @@ -354,18 +359,24 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, #ifdef ETHR_DEBUG suggested_stack_size /= 2; /* Make sure we got margin */ #endif + stack_size = ETHR_KW2B(suggested_stack_size); + stack_size = ETHR_PAGE_ALIGN(stack_size); + stack_size += ethr_pagesize__; /* For possible system usage */ #ifdef ETHR_STACK_GUARD_SIZE /* The guard is at least on some platforms included in the stack size passed when creating threads */ - suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE); + stack_size += ETHR_STACK_GUARD_SIZE; #endif - if (suggested_stack_size < ethr_min_stack_size__) - stack_size = ETHR_KW2B(ethr_min_stack_size__); - else if (suggested_stack_size > ethr_max_stack_size__) - stack_size = ETHR_KW2B(ethr_max_stack_size__); - else - stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + if (stack_size < ethr_min_stack_size__) + stack_size = ethr_min_stack_size__; + else if (stack_size > ethr_max_stack_size__) + stack_size = ethr_max_stack_size__; (void) pthread_attr_setstacksize(&attr, stack_size); + twd.stacksize = stack_size; + twd.stacksize -= ethr_pagesize__; /* For possible system usage */ +#ifdef ETHR_STACK_GUARD_SIZE + twd.stacksize -= ETHR_STACK_GUARD_SIZE; +#endif } #ifdef ETHR_STACK_GUARD_SIZE diff --git a/erts/lib_src/win/ethread.c b/erts/lib_src/win/ethread.c index e0f19f7ba1..ba77b3dc88 100644 --- a/erts/lib_src/win/ethread.c +++ b/erts/lib_src/win/ethread.c @@ -56,6 +56,7 @@ typedef struct { void *(*thr_func)(void *); void *arg; void *prep_func_res; + size_t stacksize; } ethr_thr_wrap_data__; #define ETHR_INVALID_TID_ID -1 @@ -94,6 +95,7 @@ static void thr_exit_cleanup(ethr_tid *tid, void *res) static unsigned __stdcall thr_wrapper(LPVOID vtwd) { + char c; ethr_tid my_tid; ethr_sint32_t result; void *res; @@ -102,6 +104,8 @@ static unsigned __stdcall thr_wrapper(LPVOID vtwd) void *arg = twd->arg; ethr_ts_event *tsep = NULL; + ethr_set_stacklimit__(&c, twd->stacksize); + result = (ethr_sint32_t) ethr_make_ts_event__(&tsep); if (result == 0) { @@ -305,18 +309,21 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, tid->jdata->res = NULL; } + twd.stacksize = 0; + if (use_stack_size >= 0) { size_t suggested_stack_size = (size_t) use_stack_size; #ifdef ETHR_DEBUG suggested_stack_size /= 2; /* Make sure we got margin */ #endif - if (suggested_stack_size < ethr_min_stack_size__) - stack_size = (unsigned) ETHR_KW2B(ethr_min_stack_size__); - else if (suggested_stack_size > ethr_max_stack_size__) - stack_size = (unsigned) ETHR_KW2B(ethr_max_stack_size__); - else - stack_size = (unsigned) - ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + stack_size = (unsigned) ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + + if (stack_size < (unsigned) ethr_min_stack_size__) + stack_size = (unsigned) ethr_min_stack_size__; + else if (stack_size > (unsigned) ethr_max_stack_size__) + stack_size = (unsigned) ethr_max_stack_size__; + + twd.stacksize = stack_size; } ethr_atomic32_init(&twd.result, -1); diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index 464027bade..a76ded5f60 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -612,9 +612,15 @@ pcre_cve_2008_2371(Config) when is_list(Config) -> %% http://vcs.pcre.org/viewvc/code/trunk/pcre_compile.c?r1=504&r2=505&view=patch pcre_compile_workspace_overflow(Config) when is_list(Config) -> N = 819, - {error,{"regular expression is too complicated",799}} = - re:compile([lists:duplicate(N, $(), lists:duplicate(N, $))]), - ok. + ExpStr = "Got expected error: ", + case re:compile([lists:duplicate(N, $(), lists:duplicate(N, $))]) of + {error, {"regular expression is too complicated" = Str,799}} -> + {comment, ExpStr ++ Str}; + {error, {"parentheses are too deeply nested (stack check)" = Str, _No}} -> + {comment, ExpStr ++ Str}; + Other -> + ?t:fail({unexpected, Other}) + end. %% Make sure matches that really loop infinitely actually fail. re_infinite_loop(Config) when is_list(Config) -> -- cgit v1.2.3