mirror of
https://github.com/Xahau/xahaud.git
synced 2026-04-29 15:37:46 +00:00
better exit handling accept/rollback/exception/instruction limit
This commit is contained in:
@@ -194,6 +194,7 @@ typedef enum JSErrorEnum {
|
||||
JS_INTERNAL_ERROR,
|
||||
JS_AGGREGATE_ERROR,
|
||||
JS_EXIT, /* used to close the vm down early */
|
||||
JS_INSTRUCTION_LIMIT, /* used when instruction limit is reached */
|
||||
JS_NATIVE_ERROR_COUNT, /* number of different NativeError objects */
|
||||
} JSErrorEnum;
|
||||
|
||||
@@ -6634,6 +6635,7 @@ JSValue JS_Exit(JSContext* ctx, const char* msg)
|
||||
JS_NewString(ctx, msg == 0 ? "JS_EXIT called" : msg),
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
}
|
||||
JS_SetUncatchableError(ctx, obj, TRUE);
|
||||
ret = JS_Throw(ctx, obj);
|
||||
return ret;
|
||||
}
|
||||
@@ -6778,6 +6780,23 @@ JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *c
|
||||
return val;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowInstructionLimit(JSContext *ctx)
|
||||
{
|
||||
JSValue obj, ret;
|
||||
obj = JS_NewObjectProtoClass(ctx, ctx->native_error_proto[JS_INSTRUCTION_LIMIT],
|
||||
JS_CLASS_ERROR);
|
||||
if (unlikely(JS_IsException(obj))) {
|
||||
obj = JS_NULL;
|
||||
} else {
|
||||
JS_DefinePropertyValue(ctx, obj, JS_ATOM_message,
|
||||
JS_NewString(ctx, "Instruction limit reached"),
|
||||
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
|
||||
}
|
||||
JS_SetUncatchableError(ctx, obj, TRUE);
|
||||
ret = JS_Throw(ctx, obj);
|
||||
return ret;
|
||||
}
|
||||
|
||||
JSValue JS_ThrowOutOfMemory(JSContext *ctx)
|
||||
{
|
||||
JSRuntime *rt = ctx->rt;
|
||||
@@ -6863,8 +6882,7 @@ static inline __exception int js_poll_interrupts(JSContext *ctx)
|
||||
{
|
||||
/* XXX: should set a specific flag to avoid catching */
|
||||
/* RHTODO: investigate if this is user-catchable. */
|
||||
JS_ThrowInternalError(ctx, "interrupted");
|
||||
JS_SetUncatchableError(ctx, ctx->rt->current_exception, TRUE);
|
||||
JS_ThrowInstructionLimit(ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -52644,7 +52662,7 @@ void JS_EnableBignumExt(JSContext *ctx, BOOL enable)
|
||||
static const char * const native_error_name[JS_NATIVE_ERROR_COUNT] = {
|
||||
"EvalError", "RangeError", "ReferenceError",
|
||||
"SyntaxError", "TypeError", "URIError",
|
||||
"InternalError", "AggregateError", "JSExit"
|
||||
"InternalError", "AggregateError", "Exit", "InstructionLimit"
|
||||
};
|
||||
|
||||
/* Minimum amount of objects to be able to compile code and display
|
||||
|
||||
@@ -1591,54 +1591,80 @@ public:
|
||||
val =
|
||||
JS_Eval(vm.ctx, expr, expr_len, "<qjsvm>", 0);
|
||||
|
||||
int normal_exit = 0;
|
||||
|
||||
JSValue exception_val = JS_GetException(ctx);
|
||||
if (!JS_IsUndefined(exception_val) && JS_IsError(ctx, exception_val))
|
||||
{
|
||||
JSValue exception_val = JS_GetException(ctx);
|
||||
int is_error;
|
||||
|
||||
int printed_something = 0;
|
||||
|
||||
is_error = JS_IsError(ctx, exception_val);
|
||||
// Most exceptions should have a message field, try to fetch and print that
|
||||
JSValue msg = JS_GetPropertyStr(ctx, exception_val, "message");
|
||||
if (!JS_IsUndefined(msg))
|
||||
{
|
||||
const char *str;
|
||||
|
||||
str = JS_ToCString(ctx, exception_val);
|
||||
if (str)
|
||||
if (const char *str = JS_ToCString(ctx, msg); str)
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: " << str;
|
||||
std::string m(str);
|
||||
JS_FreeCString(ctx, str);
|
||||
|
||||
if ((m == "HookExit Accept" || m == "HookExit Rollback") &&
|
||||
(hookCtx.result.exitType == hook_api::ExitType::ACCEPT ||
|
||||
hookCtx.result.exitType == hook_api::ExitType::ROLLBACK))
|
||||
{
|
||||
normal_exit = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: JSException " << m;
|
||||
printed_something++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: [exception]";
|
||||
}
|
||||
|
||||
}
|
||||
if (is_error) {
|
||||
JSValue val = JS_GetPropertyStr(ctx, exception_val, "stack");
|
||||
if (!JS_IsUndefined(val)) {
|
||||
const char *str;
|
||||
JS_FreeValue(ctx, msg);
|
||||
|
||||
str = JS_ToCString(ctx, val);
|
||||
if (str)
|
||||
// Accept/rollback are handled via an uncatchable exception internally in quickjs
|
||||
// so only print a backtrace if it isn't a normal exit.
|
||||
if (!normal_exit)
|
||||
{
|
||||
|
||||
if (!printed_something)
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: [unknown exception]";
|
||||
}
|
||||
|
||||
JSValue bt = JS_GetPropertyStr(ctx, exception_val, "stack");
|
||||
if (!normal_exit && !JS_IsUndefined(bt))
|
||||
{
|
||||
if (const char *str = JS_ToCString(ctx, bt); str)
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: " << str;
|
||||
JS_FreeCString(ctx, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.warn()) << "HookError[" << HC_ACC() << "]: [exception]";
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, val);
|
||||
}
|
||||
JS_FreeValue(ctx, exception_val);
|
||||
}
|
||||
|
||||
JS_FreeValue(ctx, bt);
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, exception_val);
|
||||
|
||||
if (normal_exit)
|
||||
{
|
||||
if (hookCtx.result.exitType == hook_api::ExitType::ACCEPT)
|
||||
{
|
||||
JLOG(j.warn()) << "HookInfo[" << HC_ACC() << "]: JSVM Exited with ACCEPT";
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.warn()) << "HookInfo[" << HC_ACC() << "]: JSVM Exited with ROLLBACK";
|
||||
}
|
||||
}
|
||||
/*
|
||||
// RHTODO: place jsvm_error exit type logic appropriately
|
||||
hookCtx.result.exitType = hook_api::ExitType::JSVM_ERROR;
|
||||
hookCtx.result.instructionCount = 0; //?
|
||||
*/
|
||||
JS_FreeValue(ctx, val);
|
||||
//JS_FreeValue(ctx, obj);
|
||||
}
|
||||
|
||||
HookExecutorJS(HookContext& ctx)
|
||||
|
||||
Reference in New Issue
Block a user