From be71d3a4b92531b01b742c7d016107876d37f3d8 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sat, 20 Mar 2021 21:06:26 +0100 Subject: [PATCH] rework allocator errors and error message storage buffer --- include/cubescript/cubescript.hh | 47 ++++++++++----------- src/cs_util.hh | 6 ++- src/cs_vm.cc | 70 +++++++++++++++++--------------- src/cubescript.cc | 14 +++++++ 4 files changed, 77 insertions(+), 60 deletions(-) diff --git a/include/cubescript/cubescript.hh b/include/cubescript/cubescript.hh index cba31c7..3fd96f4 100644 --- a/include/cubescript/cubescript.hh +++ b/include/cubescript/cubescript.hh @@ -386,14 +386,6 @@ enum class cs_loop_state { NORMAL = 0, BREAK, CONTINUE }; -static inline void *cs_default_alloc(void *, void *p, size_t, size_t ns) { - if (!ns) { - delete[] static_cast(p); - return nullptr; - } - return new unsigned char[ns]; -} - struct LIBCUBESCRIPT_EXPORT cs_state { friend struct cs_error; friend struct cs_strman; @@ -407,7 +399,8 @@ struct LIBCUBESCRIPT_EXPORT cs_state { int identflags = 0; - cs_state(cs_alloc_cb func = cs_default_alloc, void *data = nullptr); + cs_state(); + cs_state(cs_alloc_cb func, void *data); virtual ~cs_state(); cs_state(cs_state const &) = delete; @@ -536,11 +529,10 @@ private: LIBCUBESCRIPT_LOCAL void *alloc(void *ptr, size_t olds, size_t news); cs_gen_state *p_pstate = nullptr; + void *p_errbuf = nullptr; int p_inloop = 0; bool p_owner = false; - char p_errbuf[512]; - cs_hook_cb p_callhook; }; @@ -593,7 +585,11 @@ struct LIBCUBESCRIPT_EXPORT cs_error { cs_error(cs_state &cs, std::string_view msg): p_errmsg(), p_stack(cs) { - p_errmsg = save_msg(cs, msg); + char *sp; + char *buf = request_buf(cs, msg.size(), sp); + std::memcpy(buf, msg.data(), msg.size()); + buf[msg.size()] = '\0'; + p_errmsg = std::string_view{sp, buf + msg.size()}; p_stack = save_stack(cs); } @@ -601,26 +597,25 @@ struct LIBCUBESCRIPT_EXPORT cs_error { cs_error(cs_state &cs, std::string_view msg, A const &...args): p_errmsg(), p_stack(cs) { - char fbuf[512]; - int written = std::snprintf( - fbuf, sizeof(fbuf), msg.data(), args... - ); - if (written >= int(sizeof(fbuf))) { - written = std::strlen(fbuf); - } else if (written <= 0) { - std::strncpy(fbuf, "format error", sizeof(fbuf)); - written = std::strlen(fbuf); + std::size_t sz = msg.size() + 64; + char *buf, *sp; + for (;;) { + buf = request_buf(cs, sz, sp); + int written = std::snprintf(buf, sz, msg.data(), args...); + if (written <= 0) { + throw cs_internal_error{"format error"}; + } else if (std::size_t(written) <= sz) { + break; + } + sz = std::size_t(written); } - p_errmsg = save_msg(cs, std::string_view{ - static_cast(fbuf), - std::size_t(written) - }); + p_errmsg = std::string_view{sp, buf + sz}; p_stack = save_stack(cs); } private: cs_stack_state save_stack(cs_state &cs); - std::string_view save_msg(cs_state &cs, std::string_view v); + char *request_buf(cs_state &cs, std::size_t bufs, char *&sp); std::string_view p_errmsg; cs_stack_state p_stack; diff --git a/src/cs_util.hh b/src/cs_util.hh index 4fd013d..b3ac895 100644 --- a/src/cs_util.hh +++ b/src/cs_util.hh @@ -151,7 +151,11 @@ struct cs_shared_state { {} void *alloc(void *ptr, size_t os, size_t ns) { - return allocf(aptr, ptr, os, ns); + void *p = allocf(aptr, ptr, os, ns); + if (!p && ns) { + throw std::bad_alloc{}; + } + return p; } template diff --git a/src/cs_vm.cc b/src/cs_vm.cc index 4b7200f..ff6a397 100644 --- a/src/cs_vm.cc +++ b/src/cs_vm.cc @@ -70,6 +70,43 @@ bool cs_stack_state::gap() const { return p_gap; } +char *cs_error::request_buf(cs_state &cs, std::size_t bufs, char *&sp) { + cs_charbuf &cb = *static_cast(cs.p_errbuf); + cs_gen_state *gs = cs.p_pstate; + cb.clear(); + std::size_t sz = 0; + if (gs) { + /* we can attach line number */ + sz = gs->src_name.size() + 32; + for (;;) { + /* we are using so the buffer tracks the elements and therefore + * does not wipe them when we attempt to reserve more capacity + */ + cb.resize(sz); + int nsz; + if (!gs->src_name.empty()) { + nsz = std::snprintf( + cb.data(), sz, "%.*s:%zu: ", + int(gs->src_name.size()), gs->src_name.data(), + gs->current_line + ); + } else { + nsz = std::snprintf(cb.data(), sz, "%zu: ", gs->current_line); + } + if (nsz <= 0) { + throw cs_internal_error{"format error"}; + } else if (std::size_t(nsz) < sz) { + sz = std::size_t(nsz); + break; + } + sz = std::size_t(nsz + 1); + } + } + cb.resize(sz + bufs + 1); + sp = cb.data(); + return &cb[sz]; +} + cs_stack_state cs_error::save_stack(cs_state &cs) { cs_ivar *dalias = static_cast(cs.p_state->identmap[DbgaliasIdx]); if (!dalias->get_value()) { @@ -107,39 +144,6 @@ cs_stack_state cs_error::save_stack(cs_state &cs) { return cs_stack_state(cs, ret, total > dalias->get_value()); } -std::string_view cs_error::save_msg( - cs_state &cs, std::string_view msg -) { - if (msg.size() >= sizeof(cs.p_errbuf)) { - msg = msg.substr(0, sizeof(cs.p_errbuf) - 1); - } - cs_gen_state *gs = cs.p_pstate; - if (gs) { - /* we can attach line number */ - int sz; - if (!gs->src_name.empty()) { - sz = snprintf( - cs.p_errbuf, sizeof(cs.p_errbuf), "%.*s:%zu: %.*s", - int(gs->src_name.size()), gs->src_name.data(), - gs->current_line, - int(msg.size()), msg.data() - ); - } else { - sz = snprintf( - cs.p_errbuf, sizeof(cs.p_errbuf), "%zu: %.*s", - gs->current_line, int(msg.size()), msg.data() - ); - } - if (sz <= 0) { - throw cs_internal_error{"format error"}; - } - return std::string_view{cs.p_errbuf, std::size_t(sz)}; - } - memcpy(cs.p_errbuf, msg.data(), msg.size()); - cs.p_errbuf[msg.size()] = '\0'; - return std::string_view{cs.p_errbuf, msg.size()}; -} - static void bcode_ref(uint32_t *code) { if (!code) { return; diff --git a/src/cubescript.cc b/src/cubescript.cc index 56b2b1b..b552327 100644 --- a/src/cubescript.cc +++ b/src/cubescript.cc @@ -248,6 +248,16 @@ int cs_command::get_num_args() const { void cs_init_lib_base(cs_state &cs); +static void *cs_default_alloc(void *, void *p, size_t, size_t ns) { + if (!ns) { + std::free(p); + return nullptr; + } + return std::realloc(p, ns); +} + +cs_state::cs_state(): cs_state{cs_default_alloc, nullptr} {} + cs_state::cs_state(cs_alloc_cb func, void *data): p_state(nullptr), p_callhook() { @@ -262,6 +272,9 @@ cs_state::cs_state(cs_alloc_cb func, void *data): new (p_state) cs_shared_state{func, data}; p_owner = true; + /* will be used as message storage for errors */ + p_errbuf = p_state->create(*this); + for (int i = 0; i < MaxArguments; ++i) { char buf[32]; snprintf(buf, sizeof(buf), "arg%d", i + 1); @@ -379,6 +392,7 @@ LIBCUBESCRIPT_EXPORT void cs_state::destroy() { p_state->destroy(i); } p_state->destroy(p_state->strman); + p_state->destroy(static_cast(p_errbuf)); p_state->destroy(p_state); }