From 4510e539164bdfc5bfe9933cf517c33a91256b7c Mon Sep 17 00:00:00 2001 From: q66 Date: Tue, 13 Sep 2016 23:46:51 +0200 Subject: [PATCH] use normal exception handling to handle errors C++-side, also guarantee valid pointer from alloc --- include/cubescript/cubescript.hh | 85 +++++++++++++++--------- src/cs_vm.hh | 66 ------------------- src/cubescript.cc | 109 +++++++------------------------ tools/repl.cc | 18 ++--- 4 files changed, 83 insertions(+), 195 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index 691b83dc..68b14e79 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -336,6 +336,36 @@ private: bool p_gap; }; +struct CsErrorException { + friend struct CsState; + + CsErrorException() = delete; + CsErrorException(CsErrorException const &) = delete; + CsErrorException(CsErrorException &&v): + p_errmsg(v.p_errmsg), p_stack(ostd::move(v.p_stack)) + {} + + ostd::ConstCharRange what() const { + return p_errmsg; + } + + CsStackState &get_stack() { + return p_stack; + } + + CsStackState const &get_stack() const { + return p_stack; + } + +private: + CsErrorException(ostd::ConstCharRange v, CsStackState &&st): + p_errmsg(v), p_stack(ostd::move(st)) + {} + + ostd::ConstCharRange p_errmsg; + CsStackState p_stack; +}; + using CsHookCb = ostd::Function; using CsPanicCb = ostd::Function; @@ -379,15 +409,10 @@ struct OSTD_EXPORT CsState { CsIdentLink *p_callstack = nullptr; int identflags = 0; - int protect = 0; CsState(); virtual ~CsState(); - bool is_alive() const { - return bool(p_state); - } - CsStream const &get_out() const; CsStream &get_out(); void set_out(CsStream &s); @@ -407,31 +432,32 @@ struct OSTD_EXPORT CsState { )); } - virtual void *alloc(void *ptr, ostd::Size olds, ostd::Size news); + void *alloc(void *ptr, ostd::Size olds, ostd::Size news); + + template + T *create(A &&...args) { + T *ret = static_cast(alloc(nullptr, 0, sizeof(T))); + new (ret) T(ostd::forward(args)...); + return ret; + } + + template + T *create_array(ostd::Size len) { + T *ret = static_cast(alloc(nullptr, 0, len * sizeof(T))); + for (ostd::Size i = 0; i < len; ++i) { + new (&ret[i]) T(); + } + return ret; + } + + template + void destroy(T *v) noexcept { + v->~T(); + alloc(v, sizeof(T), 0); + } void init_libs(int libs = CsLibAll); - CsPanicCb set_panic_func(CsPanicCb func); - CsPanicCb const &get_panic_func() const; - CsPanicCb &get_panic_func(); - - template - CsPanicCb set_panic_func(F &&f) { - return set_panic_func(CsPanicCb( - ostd::allocator_arg, CsAllocator(*this), ostd::forward(f) - )); - } - - template - bool pcall( - F func, ostd::ConstCharRange *error = nullptr, - CsStackState *stack = nullptr - ) { - return ipcall([](void *data) { - (*static_cast(data))(); - }, error, stack, &func); - } - void error(ostd::ConstCharRange msg); template @@ -584,14 +610,9 @@ struct OSTD_EXPORT CsState { private: CsIdent *add_ident(CsIdent *id); - bool ipcall( - void (*f)(void *data), ostd::ConstCharRange *error, - CsStackState *stack, void *data - ); char p_errbuf[512]; CsHookCb p_callhook; - CsPanicCb p_panicfunc; CsStream *p_out, *p_err; }; diff --git a/src/cs_vm.hh b/src/cs_vm.hh index dc178333..5dba94cc 100644 --- a/src/cs_vm.hh +++ b/src/cs_vm.hh @@ -98,72 +98,6 @@ template constexpr ostd::Size CsTypeStorageSize = (sizeof(T) - 1) / sizeof(ostd::Uint32) + 1; -struct CsErrorException { - ostd::ConstCharRange errmsg; - CsStackState stack; - CsErrorException() = delete; - CsErrorException(CsErrorException const &) = delete; - CsErrorException(CsErrorException &&v): - errmsg(v.errmsg), stack(ostd::move(v.stack)) - {} - CsErrorException(ostd::ConstCharRange v, CsStackState &&st): - errmsg(v), stack(ostd::move(st)) - {} -}; - -inline void *cs_alloc_throw( - CsState &cs, void *ptr, ostd::Size olds, ostd::Size news -) { - void *ret = cs.alloc(ptr, olds, news); - if (news && !ret) { - cs.error("could not allocate memory"); - } - return ret; -} - -template -inline T *cs_new(CsState &cs, A &&...args) { - void *ret = cs.alloc(nullptr, 0, sizeof(T)); - if (!ret) { - return nullptr; - } - new (ret) T(ostd::forward(args)...); - return static_cast(ret); -} - -template -inline T *cs_new_array(CsState &cs, ostd::Size len) { - T *ret = static_cast(cs.alloc(nullptr, 0, len * sizeof(T))); - if (ret) { - for (ostd::Size i = 0; i < len; ++i) { - new (&ret[i]) T(); - } - } - return ret; -} - -template -inline T *cs_new_throw(CsState &cs, A &&...args) { - void *ret = cs_alloc_throw(cs, nullptr, 0, sizeof(T)); - new (ret) T(ostd::forward(args)...); - return static_cast(ret); -} - -template -inline T *cs_new_array_throw(CsState &cs, ostd::Size len) { - T *ret = static_cast(cs_alloc_throw(cs, nullptr, 0, len * sizeof(T))); - for (ostd::Size i = 0; i < len; ++i) { - new (&ret[i]) T(); - } - return ret; -} - -template -inline void cs_delete(CsState &cs, T *v) noexcept { - v->~T(); - cs.alloc(v, sizeof(T), 0); -} - CsStackState cs_save_stack(CsState &cs); template diff --git a/src/cubescript.cc b/src/cubescript.cc index 4bed52fe..41b61960 100644 --- a/src/cubescript.cc +++ b/src/cubescript.cc @@ -253,26 +253,9 @@ int CsCommand::get_num_args() const { void cs_init_lib_base(CsState &cs); CsState::CsState(): - p_state(nullptr), p_callhook(), p_panicfunc(), + p_state(create()), p_callhook(), p_out(&ostd::out), p_err(&ostd::err) { - CsSharedState *ps = static_cast( - alloc(nullptr, 0, sizeof(CsSharedState)) - ); - if (!ps) { - return; - } - /* TODO: protect with a Box */ - new (ps) CsSharedState(); - p_state = ps; - - /* default panic func */ - p_panicfunc = [](CsState &cs, ostd::ConstCharRange v, CsStackState) { - cs.get_err().writefln( - "PANIC: unprotected error in call to CubeScript (%s)", v - ); - }; - for (int i = 0; i < MaxArguments; ++i) { char buf[32]; snprintf(buf, sizeof(buf), "arg%d", i + 1); @@ -363,10 +346,9 @@ CsState::~CsState() { a->get_value().force_null(); CsAliasInternal::clean_code(a); } - delete i; + destroy(i); } - p_state->~CsSharedState(); - alloc(p_state, sizeof(CsSharedState), 0); + destroy(p_state); } CsStream const &CsState::get_out() const { @@ -408,49 +390,10 @@ CsHookCb &CsState::get_call_hook() { } void *CsState::alloc(void *ptr, ostd::Size, ostd::Size ns) { - delete[] static_cast(ptr); if (!ns) { - return nullptr; + delete static_cast(ptr); } - return new ostd::byte[ns]; -} - -CsPanicCb CsState::set_panic_func(CsPanicCb func) { - auto hk = ostd::move(p_panicfunc); - p_panicfunc = ostd::move(func); - return hk; -} - -CsPanicCb const &CsState::get_panic_func() const { - return p_panicfunc; -} - -CsPanicCb &CsState::get_panic_func() { - return p_panicfunc; -} - -bool CsState::ipcall( - void (*f)(void *data), ostd::ConstCharRange *error, - CsStackState *stack, void *data -) { - ++protect; - try { - f(data); - } catch (CsErrorException &v) { - --protect; - if (error) { - *error = v.errmsg; - } - if (stack) { - *stack = ostd::move(v.stack); - } - return false; - } catch (...) { - --protect; - throw; - } - --protect; - return true; + return new unsigned char[ns]; } void CsState::error(ostd::ConstCharRange msg) { @@ -459,14 +402,7 @@ void CsState::error(ostd::ConstCharRange msg) { } memcpy(p_errbuf, msg.data(), msg.size()); auto err = ostd::ConstCharRange(p_errbuf, msg.size()); - if (protect) { - throw CsErrorException(err, cs_save_stack(*this)); - } else { - if (p_panicfunc) { - p_panicfunc(*this, err, cs_save_stack(*this)); - } - exit(EXIT_FAILURE); - } + throw CsErrorException(err, cs_save_stack(*this)); } void CsState::clear_override(CsIdent &id) { @@ -528,7 +464,7 @@ CsIdent *CsState::new_ident(ostd::ConstCharRange name, int flags) { ); return p_state->identmap[DummyIdx]; } - id = add_ident(new CsAlias(name, flags)); + id = add_ident(create(name, flags)); } return id; } @@ -585,20 +521,24 @@ CsConstIdentRange CsState::get_idents() const { CsIvar *CsState::new_ivar( ostd::ConstCharRange n, CsInt m, CsInt x, CsInt v, CsVarCb f, int flags ) { - return add_ident(new CsIvar(n, m, x, v, ostd::move(f), flags))->get_ivar(); + return add_ident( + create(n, m, x, v, ostd::move(f), flags) + )->get_ivar(); } CsFvar *CsState::new_fvar( ostd::ConstCharRange n, CsFloat m, CsFloat x, CsFloat v, CsVarCb f, int flags ) { - return add_ident(new CsFvar(n, m, x, v, ostd::move(f), flags))->get_fvar(); + return add_ident( + create(n, m, x, v, ostd::move(f), flags) + )->get_fvar(); } CsSvar *CsState::new_svar( ostd::ConstCharRange n, CsString v, CsVarCb f, int flags ) { return add_ident( - new CsSvar(n, ostd::move(v), ostd::move(f), flags) + create(n, ostd::move(v), ostd::move(f), flags) )->get_svar(); } @@ -654,7 +594,7 @@ void CsState::set_alias(ostd::ConstCharRange name, CsValue v) { } else if (cs_check_num(name)) { cs_debug_code(*this, "cannot alias number %s", name); } else { - add_ident(new CsAlias(name, ostd::move(v), identflags)); + add_ident(create(name, ostd::move(v), identflags)); } } @@ -1084,7 +1024,7 @@ CsCommand *CsState::new_command( } } return static_cast( - add_ident(new CsCommand(name, args, nargs, ostd::move(func))) + add_ident(create(name, args, nargs, ostd::move(func))) ); } @@ -1145,21 +1085,20 @@ void cs_init_lib_base(CsState &gcs) { ret.set_int(0); return; } - ostd::ConstCharRange errmsg; CsValue result, tback; - CsStackState stack; - bool rc = cs.pcall([&cs, &args, &result]() { + bool rc = true; + try { cs.run(args[0].get_code(), result); - }, &errmsg, &stack); - ret.set_int(rc); - if (!rc) { - result.set_str(errmsg); - if (stack.get()) { + } catch (CsErrorException const &e) { + result.set_str(e.what()); + if (e.get_stack().get()) { auto app = ostd::appender(); - cscript::util::print_stack(app, stack); + cscript::util::print_stack(app, e.get_stack()); tback.set_str(ostd::move(app.get())); } + rc = false; } + ret.set_int(rc); CsAliasInternal::set_alias(cret, cs, result); if (css->get_index() != DummyIdx) { CsAliasInternal::set_alias(css, cs, tback); diff --git a/tools/repl.cc b/tools/repl.cc index ca09c26e..41103e40 100644 --- a/tools/repl.cc +++ b/tools/repl.cc @@ -194,9 +194,7 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { CsValue ret; scs = &cs; signal(SIGINT, do_sigint); - ostd::ConstCharRange err; - cscript::CsStackState st; - auto tocall = [&]() { + try { if (file) { if (!cs.run_file(line, ret)) { ostd::err.writeln("cannot read file: ", line); @@ -204,11 +202,10 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { } else { cs.run(line, ret); } - }; - if (!cs.pcall(ostd::move(tocall), &err, &st)) { + } catch (cscript::CsErrorException const &e) { signal(SIGINT, SIG_DFL); scs = nullptr; - ostd::ConstCharRange terr = err; + ostd::ConstCharRange terr = e.what(); auto col = ostd::find(terr, ':'); if (!col.empty()) { terr = col + 2; @@ -216,9 +213,9 @@ static bool do_call(CsState &cs, ostd::ConstCharRange line, bool file = false) { if (!file && ((terr == "missing \"]\"") || (terr == "missing \")\""))) { return true; } - cs.get_out().writeln(col.empty() ? "stdin: " : "stdin:", err); - if (st.get()) { - cscript::util::print_stack(cs.get_out().iter(), st); + cs.get_out().writeln(col.empty() ? "stdin: " : "stdin:", e.what()); + if (e.get_stack().get()) { + cscript::util::print_stack(cs.get_out().iter(), e.get_stack()); cs.get_out().write('\n'); } return false; @@ -273,9 +270,6 @@ static void do_tty(CsState &cs) { int main(int argc, char **argv) { CsState gcs; - if (!gcs.is_alive()) { - return 1; - } gcs.init_libs(); gcs.new_command("exec", "sb", [](CsState &cs, auto args, auto &res) {