use normal exception handling to handle errors C++-side, also guarantee valid pointer from alloc

master
Daniel Kolesa 2016-09-13 23:46:51 +02:00
parent 35ebb0e822
commit 4510e53916
4 changed files with 83 additions and 195 deletions

View File

@ -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<void(CsState &)>;
using CsPanicCb =
ostd::Function<void(CsState &, ostd::ConstCharRange, CsStackState)>;
@ -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<typename T, typename ...A>
T *create(A &&...args) {
T *ret = static_cast<T *>(alloc(nullptr, 0, sizeof(T)));
new (ret) T(ostd::forward<A>(args)...);
return ret;
}
template<typename T>
T *create_array(ostd::Size len) {
T *ret = static_cast<T *>(alloc(nullptr, 0, len * sizeof(T)));
for (ostd::Size i = 0; i < len; ++i) {
new (&ret[i]) T();
}
return ret;
}
template<typename T>
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<typename F>
CsPanicCb set_panic_func(F &&f) {
return set_panic_func(CsPanicCb(
ostd::allocator_arg, CsAllocator<char>(*this), ostd::forward<F>(f)
));
}
template<typename F>
bool pcall(
F func, ostd::ConstCharRange *error = nullptr,
CsStackState *stack = nullptr
) {
return ipcall([](void *data) {
(*static_cast<F *>(data))();
}, error, stack, &func);
}
void error(ostd::ConstCharRange msg);
template<typename ...A>
@ -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;
};

View File

@ -98,72 +98,6 @@ template<typename T>
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<typename T, typename ...A>
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<A>(args)...);
return static_cast<T *>(ret);
}
template<typename T>
inline T *cs_new_array(CsState &cs, ostd::Size len) {
T *ret = static_cast<T *>(cs.alloc(nullptr, 0, len * sizeof(T)));
if (ret) {
for (ostd::Size i = 0; i < len; ++i) {
new (&ret[i]) T();
}
}
return ret;
}
template<typename T, typename ...A>
inline T *cs_new_throw(CsState &cs, A &&...args) {
void *ret = cs_alloc_throw(cs, nullptr, 0, sizeof(T));
new (ret) T(ostd::forward<A>(args)...);
return static_cast<T *>(ret);
}
template<typename T>
inline T *cs_new_array_throw(CsState &cs, ostd::Size len) {
T *ret = static_cast<T *>(cs_alloc_throw(cs, nullptr, 0, len * sizeof(T)));
for (ostd::Size i = 0; i < len; ++i) {
new (&ret[i]) T();
}
return ret;
}
template<typename T>
inline void cs_delete(CsState &cs, T *v) noexcept {
v->~T();
cs.alloc(v, sizeof(T), 0);
}
CsStackState cs_save_stack(CsState &cs);
template<typename ...A>

View File

@ -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<CsSharedState>()), p_callhook(),
p_out(&ostd::out), p_err(&ostd::err)
{
CsSharedState *ps = static_cast<CsSharedState *>(
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<ostd::byte *>(ptr);
if (!ns) {
return nullptr;
delete static_cast<unsigned char *>(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<CsAlias>(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<CsIvar>(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<CsFvar>(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<CsSvar>(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<CsAlias>(name, ostd::move(v), identflags));
}
}
@ -1084,7 +1024,7 @@ CsCommand *CsState::new_command(
}
}
return static_cast<CsCommand *>(
add_ident(new CsCommand(name, args, nargs, ostd::move(func)))
add_ident(create<CsCommand>(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<CsString>();
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);

View File

@ -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) {