Skip to content

Commit 7f1c981

Browse files
committed
vm: Support strict stackless mode, with proper exception reporting.
I.e. in this mode, C stack will never be used to call a Python function, but if there's no free heap for a call, it will be reported as RuntimeError (as expected), not MemoryError.
1 parent f0a8f21 commit 7f1c981

4 files changed

Lines changed: 38 additions & 3 deletions

File tree

py/mpconfig.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,19 @@
125125
#define MICROPY_QSTR_BYTES_IN_LEN (1)
126126
#endif
127127

128-
// Avoid using C stack when making Python function calls.
128+
// Avoid using C stack when making Python function calls. C stack still
129+
// may be used if there's no free heap.
129130
#ifndef MICROPY_STACKLESS
130131
#define MICROPY_STACKLESS (0)
131132
#endif
132133

134+
// Never use C stack when making Python function calls. This may break
135+
// testsuite as will subtly change which exception is thrown in case
136+
// of too deep recursion and other similar cases.
137+
#ifndef MICROPY_STACKLESS_STRICT
138+
#define MICROPY_STACKLESS_STRICT (0)
139+
#endif
140+
133141
/*****************************************************************************/
134142
/* Micro Python emitters */
135143

py/runtime.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ void mp_import_all(mp_obj_t module);
130130

131131
// Raise NotImplementedError with given message
132132
NORETURN void mp_not_implemented(const char *msg);
133+
NORETURN void mp_exc_recursion_depth(void);
133134

134135
// helper functions for native/viper code
135136
mp_uint_t mp_convert_obj_to_native(mp_obj_t obj, mp_uint_t type);

py/stackctrl.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "py/mpstate.h"
2828
#include "py/nlr.h"
2929
#include "py/obj.h"
30+
#include "py/runtime.h"
3031
#include "py/stackctrl.h"
3132

3233
void mp_stack_ctrl_init(void) {
@@ -46,10 +47,14 @@ void mp_stack_set_limit(mp_uint_t limit) {
4647
MP_STATE_VM(stack_limit) = limit;
4748
}
4849

50+
void mp_exc_recursion_depth(void) {
51+
nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
52+
MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));
53+
}
54+
4955
void mp_stack_check(void) {
5056
if (mp_stack_usage() >= MP_STATE_VM(stack_limit)) {
51-
nlr_raise(mp_obj_new_exception_arg1(&mp_type_RuntimeError,
52-
MP_OBJ_NEW_QSTR(MP_QSTR_maximum_space_recursion_space_depth_space_exceeded)));
57+
mp_exc_recursion_depth();
5358
}
5459
}
5560

py/vm.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,12 @@ unwind_jump:;
880880
nlr_pop();
881881
goto run_code_state;
882882
}
883+
#if MICROPY_STACKLESS_STRICT
884+
else {
885+
deep_recursion_error:
886+
mp_exc_recursion_depth();
887+
}
888+
#endif
883889
}
884890
#endif
885891
SET_TOP(mp_call_function_n_kw(*sp, unum & 0xff, (unum >> 8) & 0xff, sp + 1));
@@ -912,6 +918,11 @@ unwind_jump:;
912918
nlr_pop();
913919
goto run_code_state;
914920
}
921+
#if MICROPY_STACKLESS_STRICT
922+
else {
923+
goto deep_recursion_error;
924+
}
925+
#endif
915926
}
916927
#endif
917928
SET_TOP(mp_call_method_n_kw_var(false, unum, sp));
@@ -941,6 +952,11 @@ unwind_jump:;
941952
nlr_pop();
942953
goto run_code_state;
943954
}
955+
#if MICROPY_STACKLESS_STRICT
956+
else {
957+
goto deep_recursion_error;
958+
}
959+
#endif
944960
}
945961
#endif
946962
SET_TOP(mp_call_method_n_kw(unum & 0xff, (unum >> 8) & 0xff, sp));
@@ -973,6 +989,11 @@ unwind_jump:;
973989
nlr_pop();
974990
goto run_code_state;
975991
}
992+
#if MICROPY_STACKLESS_STRICT
993+
else {
994+
goto deep_recursion_error;
995+
}
996+
#endif
976997
}
977998
#endif
978999
SET_TOP(mp_call_method_n_kw_var(true, unum, sp));

0 commit comments

Comments
 (0)