memory safe error stack state
parent
3189d87ac9
commit
8086c23a77
|
@ -40,9 +40,12 @@ struct LIBCUBESCRIPT_EXPORT error {
|
||||||
* index 1 and the one above it greater than 2). The gap is controlled
|
* index 1 and the one above it greater than 2). The gap is controlled
|
||||||
* by the value of the `dbgalias` cubescript variable at the time of
|
* by the value of the `dbgalias` cubescript variable at the time of
|
||||||
* creation of the error (the stack list will contain at most N nodes).
|
* creation of the error (the stack list will contain at most N nodes).
|
||||||
|
*
|
||||||
|
* When getting the stack state, it will be represented as a span with
|
||||||
|
* the first element being the topmost node and the last element being
|
||||||
|
* the bottommost (index 1).
|
||||||
*/
|
*/
|
||||||
struct stack_node {
|
struct stack_node {
|
||||||
stack_node const *next; /**< @brief Next level. */
|
|
||||||
struct ident const &id; /**< @brief The ident of this level. */
|
struct ident const &id; /**< @brief The ident of this level. */
|
||||||
std::size_t index; /**< @brief The level index. */
|
std::size_t index; /**< @brief The level index. */
|
||||||
};
|
};
|
||||||
|
@ -51,10 +54,12 @@ struct LIBCUBESCRIPT_EXPORT error {
|
||||||
error(error const &) = delete;
|
error(error const &) = delete;
|
||||||
|
|
||||||
/** @brief Errors are move constructible. */
|
/** @brief Errors are move constructible. */
|
||||||
error(error &&v):
|
error(error &&v);
|
||||||
p_errbeg{v.p_errbeg}, p_errend{v.p_errend},
|
|
||||||
p_stack{std::move(v.p_stack)}, p_state{v.p_state}
|
error &operator=(error const &) = delete;
|
||||||
{}
|
|
||||||
|
/** @brief Errors are move assignable. */
|
||||||
|
error &operator=(error &&v);
|
||||||
|
|
||||||
/** @brief Construct an error using a string. */
|
/** @brief Construct an error using a string. */
|
||||||
error(state &cs, std::string_view msg);
|
error(state &cs, std::string_view msg);
|
||||||
|
@ -63,26 +68,18 @@ struct LIBCUBESCRIPT_EXPORT error {
|
||||||
~error();
|
~error();
|
||||||
|
|
||||||
/** @brief Get a view of the error message. */
|
/** @brief Get a view of the error message. */
|
||||||
std::string_view what() const {
|
std::string_view what() const;
|
||||||
return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Get a reference to the call stack state. */
|
/** @brief Get the call stack state at the point of error. */
|
||||||
stack_node *stack() {
|
span_type<stack_node const> stack() const;
|
||||||
return p_stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Get a reference to the call stack state. */
|
|
||||||
stack_node const *stack() const {
|
|
||||||
return p_stack;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
friend struct error_p;
|
friend struct error_p;
|
||||||
|
|
||||||
error(state &cs, char const *errbeg, char const *errend);
|
error(state &cs, char const *errbeg, char const *errend);
|
||||||
|
|
||||||
char const *p_errbeg, *p_errend;
|
char const *p_errbeg, *p_errend;
|
||||||
stack_node *p_stack;
|
stack_node *p_sbeg, *p_send;
|
||||||
state *p_state;
|
state *p_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,35 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "cs_thread.hh"
|
#include "cs_thread.hh"
|
||||||
#include "cs_error.hh"
|
#include "cs_error.hh"
|
||||||
|
|
||||||
namespace cubescript {
|
namespace cubescript {
|
||||||
|
|
||||||
static typename error::stack_node *save_stack(state &cs) {
|
static void save_stack(
|
||||||
|
state &cs, typename error::stack_node *&sbeg,
|
||||||
|
typename error::stack_node *&send
|
||||||
|
) {
|
||||||
auto &ts = state_p{cs}.ts();
|
auto &ts = state_p{cs}.ts();
|
||||||
builtin_var *dalias = ts.istate->ivar_dbgalias;
|
builtin_var *dalias = ts.istate->ivar_dbgalias;
|
||||||
auto dval = std::size_t(std::clamp(
|
auto dval = std::size_t(std::clamp(
|
||||||
dalias->value().get_integer(), integer_type(0), integer_type(1000)
|
dalias->value().get_integer(), integer_type(0), integer_type(1000)
|
||||||
));
|
));
|
||||||
if (!dval) {
|
if (!dval) {
|
||||||
return nullptr;
|
sbeg = send = nullptr;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
std::size_t depth = 0;
|
std::size_t depth = 0;
|
||||||
std::size_t total = ts.callstack.size();
|
std::size_t total = ts.callstack.size();
|
||||||
if (!total) {
|
if (!total) {
|
||||||
return nullptr;
|
sbeg = send = nullptr;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
auto slen = std::min(total, dval);
|
||||||
auto *st = static_cast<typename error::stack_node *>(ts.istate->alloc(
|
auto *st = static_cast<typename error::stack_node *>(ts.istate->alloc(
|
||||||
nullptr, 0, sizeof(typename error::stack_node) * std::min(total, dval)
|
nullptr, 0, sizeof(typename error::stack_node) * slen
|
||||||
));
|
));
|
||||||
typename error::stack_node *ret = st, *nd = st;
|
typename error::stack_node *ret = st, *nd = st;
|
||||||
++st;
|
++st;
|
||||||
|
@ -32,27 +39,41 @@ static typename error::stack_node *save_stack(state &cs) {
|
||||||
++depth;
|
++depth;
|
||||||
if (depth < dval) {
|
if (depth < dval) {
|
||||||
new (nd) typename error::stack_node{
|
new (nd) typename error::stack_node{
|
||||||
nullptr, lev.id, total - depth + 1
|
lev.id, total - depth + 1
|
||||||
};
|
};
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
nd->next = st;
|
|
||||||
nd = st++;
|
nd = st++;
|
||||||
} else if (i == 0) {
|
} else if (i == 0) {
|
||||||
new (nd) typename error::stack_node{nullptr, lev.id, 1};
|
new (nd) typename error::stack_node{lev.id, 1};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
sbeg = ret;
|
||||||
|
send = ret + slen;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBCUBESCRIPT_EXPORT error::error(error &&v):
|
||||||
|
p_errbeg{v.p_errbeg}, p_errend{v.p_errend},
|
||||||
|
p_sbeg{v.p_sbeg}, p_send{v.p_send}, p_state{v.p_state}
|
||||||
|
{
|
||||||
|
v.p_sbeg = v.p_send = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LIBCUBESCRIPT_EXPORT error &error::operator=(error &&v) {
|
||||||
|
std::swap(p_errbeg, v.p_errbeg);
|
||||||
|
std::swap(p_errend, v.p_errend);
|
||||||
|
std::swap(p_sbeg, v.p_sbeg);
|
||||||
|
std::swap(p_send, v.p_send);
|
||||||
|
std::swap(p_state, v.p_state);
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT error::~error() {
|
LIBCUBESCRIPT_EXPORT error::~error() {
|
||||||
std::size_t slen = 0;
|
state_p{*p_state}.ts().istate->destroy_array(
|
||||||
for (stack_node const *nd = p_stack; nd; nd = nd->next) {
|
p_sbeg, std::size_t(p_send - p_sbeg)
|
||||||
++slen;
|
);
|
||||||
}
|
|
||||||
state_p{*p_state}.ts().istate->destroy_array(p_stack, slen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg):
|
LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg):
|
||||||
|
@ -64,13 +85,23 @@ LIBCUBESCRIPT_EXPORT error::error(state &cs, std::string_view msg):
|
||||||
buf[msg.size()] = '\0';
|
buf[msg.size()] = '\0';
|
||||||
p_errbeg = sp;
|
p_errbeg = sp;
|
||||||
p_errend = buf + msg.size();
|
p_errend = buf + msg.size();
|
||||||
p_stack = save_stack(cs);
|
save_stack(cs, p_sbeg, p_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
LIBCUBESCRIPT_EXPORT error::error(
|
LIBCUBESCRIPT_EXPORT error::error(
|
||||||
state &cs, char const *errbeg, char const *errend
|
state &cs, char const *errbeg, char const *errend
|
||||||
): p_errbeg{errbeg}, p_errend{errend}, p_state{&cs} {
|
): p_errbeg{errbeg}, p_errend{errend}, p_state{&cs} {
|
||||||
p_stack = save_stack(cs);
|
save_stack(cs, p_sbeg, p_send);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view error::what() const {
|
||||||
|
return std::string_view{p_errbeg, std::size_t(p_errend - p_errbeg)};
|
||||||
|
}
|
||||||
|
|
||||||
|
span_type<typename error::stack_node const> error::stack() const {
|
||||||
|
return span_type<typename error::stack_node const>{
|
||||||
|
p_sbeg, std::size_t(p_send - p_sbeg)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* namespace cubescript */
|
} /* namespace cubescript */
|
||||||
|
|
|
@ -84,19 +84,18 @@ LIBCUBESCRIPT_EXPORT void std_init_base(state &gcs) {
|
||||||
auto tb = any_value{};
|
auto tb = any_value{};
|
||||||
val.set_string(e.what(), cs);
|
val.set_string(e.what(), cs);
|
||||||
ts.get_astack(ra).set_alias(ra, ts, val);
|
ts.get_astack(ra).set_alias(ra, ts, val);
|
||||||
if (auto *snd = e.stack(); snd) {
|
if (auto nds = e.stack(); !nds.empty()) {
|
||||||
auto bc = args[4].get_code();
|
auto bc = args[4].get_code();
|
||||||
if (!bc.empty()) {
|
if (!bc.empty()) {
|
||||||
alias_local ist{cs, args[2].get_ident(cs)};
|
alias_local ist{cs, args[2].get_ident(cs)};
|
||||||
alias_local vst{cs, args[3].get_ident(cs)};
|
alias_local vst{cs, args[3].get_ident(cs)};
|
||||||
any_value idv{};
|
any_value idv{};
|
||||||
while (snd) {
|
for (auto &nd: nds) {
|
||||||
idv.set_integer(integer_type(snd->index));
|
idv.set_integer(integer_type(nd.index));
|
||||||
ist.set(idv);
|
ist.set(idv);
|
||||||
idv.set_string(snd->id.name().data(), cs);
|
idv.set_string(nd.id.name().data(), cs);
|
||||||
vst.set(idv);
|
vst.set(idv);
|
||||||
bc.call(cs);
|
bc.call(cs);
|
||||||
snd = snd->next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,13 +254,13 @@ static bool do_call(cs::state &cs, std::string_view line, bool file = false) {
|
||||||
"%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data()
|
"%s%s\n", !is_lnum ? "stdin: " : "stdin:", e.what().data()
|
||||||
);
|
);
|
||||||
std::size_t pindex = 1;
|
std::size_t pindex = 1;
|
||||||
for (auto *nd = e.stack(); nd; nd = nd->next) {
|
for (auto &nd: e.stack()) {
|
||||||
std::printf(" ");
|
std::printf(" ");
|
||||||
if ((nd->index == 1) && (pindex > 2)) {
|
if ((nd.index == 1) && (pindex > 2)) {
|
||||||
std::printf("..");
|
std::printf("..");
|
||||||
}
|
}
|
||||||
pindex = nd->index;
|
pindex = nd.index;
|
||||||
std::printf("%zu) %s\n", nd->index, nd->id.name().data());
|
std::printf("%zu) %s\n", nd.index, nd.id.name().data());
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue