rework allocator errors and error message storage buffer

master
Daniel Kolesa 2021-03-20 21:06:26 +01:00
parent d7c93fa8b9
commit be71d3a4b9
4 changed files with 77 additions and 60 deletions

View File

@ -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<unsigned char *>(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<char const *>(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;

View File

@ -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<typename T, typename ...A>

View File

@ -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_charbuf *>(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_ivar *>(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;

View File

@ -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<cs_charbuf>(*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<cs_charbuf *>(p_errbuf));
p_state->destroy(p_state);
}