exception-proof rundepth

master
Daniel Kolesa 2016-09-23 21:04:52 +02:00
parent 1cdcc438cc
commit 3a0cd8d378
1 changed files with 16 additions and 10 deletions

View File

@ -491,6 +491,19 @@ static inline void cs_call_alias(
static constexpr int MaxRunDepth = 255; static constexpr int MaxRunDepth = 255;
static thread_local int rundepth = 0; static thread_local int rundepth = 0;
struct RunDepthRef {
RunDepthRef() = delete;
RunDepthRef(CsState &cs) {
if (rundepth >= MaxRunDepth) {
throw CsErrorException(cs, "exceeded recursion limit");
}
++rundepth;
}
RunDepthRef(RunDepthRef const &) = delete;
RunDepthRef(RunDepthRef &&) = delete;
~RunDepthRef() { --rundepth; }
};
static inline CsAlias *cs_get_lookup_id(CsState &cs, ostd::Uint32 op) { static inline CsAlias *cs_get_lookup_id(CsState &cs, ostd::Uint32 op) {
CsIdent *id = cs.p_state->identmap[op >> 8]; CsIdent *id = cs.p_state->identmap[op >> 8];
if (id->get_flags() & CsIdfUnknown) { if (id->get_flags() & CsIdfUnknown) {
@ -550,10 +563,7 @@ static inline int cs_get_lookupu_type(
static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) { static ostd::Uint32 *runcode(CsState &cs, ostd::Uint32 *code, CsValue &result) {
result.set_null(); result.set_null();
if (rundepth >= MaxRunDepth) { RunDepthRef level{cs}; /* incr and decr on scope exit */
throw CsErrorException(cs, "exceeded recursion limit");
}
++rundepth;
int numargs = 0; int numargs = 0;
CsValue args[MaxArguments + MaxResults]; CsValue args[MaxArguments + MaxResults];
auto &chook = cs.get_call_hook(); auto &chook = cs.get_call_hook();
@ -1564,7 +1574,6 @@ noid:
} }
} }
exit: exit:
--rundepth;
return code; return code;
} }
@ -1594,10 +1603,8 @@ void CsState::run(ostd::ConstCharRange code, CsValue &ret) {
void CsState::run(CsIdent *id, CsValueRange args, CsValue &ret) { void CsState::run(CsIdent *id, CsValueRange args, CsValue &ret) {
int nargs = int(args.size()); int nargs = int(args.size());
ret.set_null(); ret.set_null();
++rundepth; RunDepthRef level{*this}; /* incr and decr on scope exit */
if (rundepth > MaxRunDepth) { if (id) {
throw CsErrorException(*this, "exceeded recursion limit");
} else if (id) {
switch (id->get_type()) { switch (id->get_type()) {
default: default:
if (!CsCommandInternal::has_cb(id)) { if (!CsCommandInternal::has_cb(id)) {
@ -1662,7 +1669,6 @@ void CsState::run(CsIdent *id, CsValueRange args, CsValue &ret) {
} }
} }
} }
--rundepth;
} }
CsString CsState::run_str(CsBytecode *code) { CsString CsState::run_str(CsBytecode *code) {