diff --git a/src/cs_ident.cc b/src/cs_ident.cc index 8771870..2d08cb4 100644 --- a/src/cs_ident.cc +++ b/src/cs_ident.cc @@ -358,14 +358,19 @@ LIBCUBESCRIPT_EXPORT any_value command::call( auto nargs = args.size(); auto &ts = state_p{cs}.ts(); if (nargs < std::size_t(cimpl.arg_count())) { - stack_guard s{ts}; /* restore after call */ auto &targs = ts.vmstack; auto osz = targs.size(); targs.resize(osz + cimpl.arg_count()); - for (std::size_t i = 0; i < nargs; ++i) { - targs[osz + i] = args[i]; + try { + for (std::size_t i = 0; i < nargs; ++i) { + targs[osz + i] = args[i]; + } + exec_command(ts, &cimpl, this, &targs[osz], ret, nargs, false); + } catch (...) { + targs.resize(osz); + throw; } - exec_command(ts, &cimpl, this, &targs[osz], ret, nargs, false); + targs.resize(osz); } else { exec_command(ts, &cimpl, this, &args[0], ret, nargs, false); } diff --git a/src/cs_state.cc b/src/cs_state.cc index 7077d88..93dc0a1 100644 --- a/src/cs_state.cc +++ b/src/cs_state.cc @@ -517,16 +517,19 @@ LIBCUBESCRIPT_EXPORT any_value state::lookup_value(std::string_view name) { return static_cast(id)->value(); case ident_type::COMMAND: { any_value val{}; - /* make sure value stack gets restored */ - stack_guard s{*p_tstate}; auto *cimpl = static_cast(id); auto &args = p_tstate->vmstack; auto osz = args.size(); /* pad with as many empty values as we need */ args.resize(osz + cimpl->arg_count()); - exec_command( - *p_tstate, cimpl, cimpl, &args[osz], val, 0, true - ); + try { + exec_command( + *p_tstate, cimpl, cimpl, &args[osz], val, 0, true + ); + } catch (...) { + args.resize(osz); + throw; + } args.resize(osz); return val; } diff --git a/src/cs_vm.cc b/src/cs_vm.cc index a18e268..ce32e7b 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -216,15 +216,6 @@ bool exec_alias( return true; } -call_depth_guard::call_depth_guard(thread_state &ts): tsp(&ts) { - if (ts.max_call_depth && (ts.call_depth >= ts.max_call_depth)) { - throw error{*ts.pstate, "exceeded recursion limit"}; - } - ++ts.call_depth; -} - -call_depth_guard::~call_depth_guard() { --tsp->call_depth; } - static inline alias *get_lookup_id( thread_state &ts, std::uint32_t op, alias_stack *&ast ) { @@ -247,13 +238,29 @@ static inline alias *get_lookup_id( return static_cast(id); } +struct vm_guard { + vm_guard(thread_state &s): ts{s}, oldtop{s.vmstack.size()} { + if (s.max_call_depth && (s.call_depth >= s.max_call_depth)) { + throw error{*s.pstate, "exceeded recursion limit"}; + } + ++s.call_depth; + } + + ~vm_guard() { + --ts.call_depth; + ts.vmstack.resize(oldtop); + } + + thread_state &ts; + std::size_t oldtop; +}; + std::uint32_t *vm_exec( thread_state &ts, std::uint32_t *code, any_value &result ) { result.set_none(); auto &cs = *ts.pstate; - call_depth_guard level{ts}; /* incr and decr on scope exit */ - stack_guard guard{ts}; /* resize back to original */ + vm_guard scope{ts}; /* keep track of recursion depth + manage stack */ auto &args = ts.vmstack; auto &chook = cs.call_hook(); if (chook) { diff --git a/src/cs_vm.hh b/src/cs_vm.hh index 59d6df1..690fa4b 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -17,33 +17,6 @@ struct break_exception { struct continue_exception { }; -struct call_depth_guard { - call_depth_guard() = delete; - call_depth_guard(thread_state &ts); - call_depth_guard(call_depth_guard const &) = delete; - call_depth_guard(call_depth_guard &&) = delete; - ~call_depth_guard(); - - thread_state *tsp; -}; - -struct stack_guard { - thread_state *tsp; - std::size_t oldtop; - - stack_guard() = delete; - stack_guard(thread_state &ts): - tsp{&ts}, oldtop{ts.vmstack.size()} - {} - - ~stack_guard() { - tsp->vmstack.resize(oldtop); - } - - stack_guard(stack_guard const &) = delete; - stack_guard(stack_guard &&) = delete; -}; - template static void call_with_args(thread_state &ts, F body, A &&...args) { if (!ts.callstack) {