diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2012-12-05 07:16:08 -0800 |
|---|---|---|
| committer | Yukihiro "Matz" Matsumoto <[email protected]> | 2012-12-05 07:16:08 -0800 |
| commit | 40daee12cfbf6dac4421f47c9c953788985fe238 (patch) | |
| tree | 32e8908c65d3b08a4e39f56c902b02682cc314ee /src | |
| parent | 222bd9722398709c42cd4739ea53832e05d7c652 (diff) | |
| parent | 039679f1af32af9c285ce1fff2d9e8fd52af51eb (diff) | |
| download | mruby-40daee12cfbf6dac4421f47c9c953788985fe238.tar.gz mruby-40daee12cfbf6dac4421f47c9c953788985fe238.zip | |
Merge pull request #567 from beoran/beoran_stack_overflow_fix
Keep stack depth and allocation better under control and fix crash on infinite recursion.
Diffstat (limited to 'src')
| -rw-r--r-- | src/vm.c | 35 |
1 files changed, 29 insertions, 6 deletions
@@ -38,6 +38,19 @@ #define STACK_INIT_SIZE 128 #define CALLINFO_INIT_SIZE 32 +/* Define amount of linear stack growth. */ +#ifndef MRB_STACK_GROWTH +#define MRB_STACK_GROWTH 128 +#endif + +/* Maximum stack depth. Should be set lower on memory constrained systems. +The value below allows about 60000 recursive calls in the simplest case. */ +#ifndef MRB_STACK_MAX +#define MRB_STACK_MAX ((1<<18) - MRB_STACK_GROWTH) +#endif + + + static inline void stack_copy(mrb_value *dst, const mrb_value *src, size_t size) { @@ -52,7 +65,7 @@ static void stack_init(mrb_state *mrb) { /* assert(mrb->stack == NULL); */ - mrb->stbase = (mrb_value *)mrb_calloc(mrb, STACK_INIT_SIZE, sizeof(mrb_value)); + mrb->stbase = (mrb_value *)mrb_calloc(mrb, STACK_INIT_SIZE, sizeof(mrb_value)); mrb->stend = mrb->stbase + STACK_INIT_SIZE; mrb->stack = mrb->stbase; @@ -79,29 +92,39 @@ envadjust(mrb_state *mrb, mrb_value *oldbase, mrb_value *newbase) } } +/** def rec ; $deep =+ 1 ; if $deep > 1000 ; return 0 ; end ; rec ; end */ + static void stack_extend(mrb_state *mrb, int room, int keep) { int size, off; - if (mrb->stack + room >= mrb->stend) { mrb_value *oldbase = mrb->stbase; size = mrb->stend - mrb->stbase; off = mrb->stack - mrb->stbase; - - if (room <= size) /* double size is enough? */ - size *= 2; + + /* Use linear stack growth. + It is slightly slower than doubling thestack space, + but it saves memory on small devices. */ + if (room <= size) + size += MRB_STACK_GROWTH; else size += room; + mrb->stbase = (mrb_value *)mrb_realloc(mrb, mrb->stbase, sizeof(mrb_value) * size); mrb->stack = mrb->stbase + off; mrb->stend = mrb->stbase + size; envadjust(mrb, oldbase, mrb->stbase); + /* Raise an exception if the new stack size will be too large, + to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raisef has stack space to work with. */ + if(size > MRB_STACK_MAX) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "stack level too deep. (limit=%d)", MRB_STACK_MAX); + } } + if (room > keep) { int i; - for (i=keep; i<room; i++) { #ifndef MRB_NAN_BOXING static const mrb_value mrb_value_zero = { { 0 } }; |
