Web: Fix timeout
This commit is contained in:
parent
9cbefa1003
commit
699c5f7af4
|
@ -559,6 +559,14 @@ void vm::run(const codegen& gen,
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
// using labels as values/computed goto
|
// using labels as values/computed goto
|
||||||
|
|
||||||
|
// Define an interrupt check macro for computed goto mode.
|
||||||
|
#define CHECK_INTERRUPT { \
|
||||||
|
if (interrupt_ptr && interrupt_ptr->load()) { \
|
||||||
|
throw std::runtime_error("VM execution interrupted by timeout"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
const void* oprs[] = {
|
const void* oprs[] = {
|
||||||
&&vmexit,
|
&&vmexit,
|
||||||
&&repl,
|
&&repl,
|
||||||
|
@ -654,7 +662,7 @@ void vm::run(const codegen& gen,
|
||||||
code.push_back(oprs[i.op]);
|
code.push_back(oprs[i.op]);
|
||||||
imm.push_back(i.num);
|
imm.push_back(i.num);
|
||||||
}
|
}
|
||||||
// goto the first operand
|
CHECK_INTERRUPT;
|
||||||
goto *code[ctx.pc];
|
goto *code[ctx.pc];
|
||||||
#else
|
#else
|
||||||
std::vector<nasal_vm_func> code;
|
std::vector<nasal_vm_func> code;
|
||||||
|
@ -663,6 +671,9 @@ void vm::run(const codegen& gen,
|
||||||
imm.push_back(i.num);
|
imm.push_back(i.num);
|
||||||
}
|
}
|
||||||
while(code[ctx.pc]) {
|
while(code[ctx.pc]) {
|
||||||
|
if (interrupt_ptr && interrupt_ptr->load()) {
|
||||||
|
throw std::runtime_error("VM execution interrupted by timeout");
|
||||||
|
}
|
||||||
(this->*code[ctx.pc])();
|
(this->*code[ctx.pc])();
|
||||||
if (ctx.top>=ctx.canary) {
|
if (ctx.top>=ctx.canary) {
|
||||||
die("stack overflow");
|
die("stack overflow");
|
||||||
|
@ -693,6 +704,7 @@ vmexit:
|
||||||
// do not cause stackoverflow
|
// do not cause stackoverflow
|
||||||
#define exec_nodie(op) {\
|
#define exec_nodie(op) {\
|
||||||
op();\
|
op();\
|
||||||
|
CHECK_INTERRUPT;\
|
||||||
goto *code[++ctx.pc];\
|
goto *code[++ctx.pc];\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -318,6 +318,13 @@ public:
|
||||||
void set_limit_mode_flag(bool flag) {
|
void set_limit_mode_flag(bool flag) {
|
||||||
flag_limited_mode = flag;
|
flag_limited_mode = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_interrupt_ptr(std::atomic<bool>* p) {
|
||||||
|
interrupt_ptr = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<bool>* interrupt_ptr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool vm::boolify(const var& val) {
|
inline bool vm::boolify(const var& val) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <future>
|
#include <future>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Helper function implementations inside anonymous namespace
|
// Helper function implementations inside anonymous namespace
|
||||||
|
@ -46,9 +47,15 @@ struct NasalContext {
|
||||||
std::string last_result;
|
std::string last_result;
|
||||||
std::string last_error;
|
std::string last_error;
|
||||||
std::chrono::seconds timeout{5}; // Default 5 second timeout
|
std::chrono::seconds timeout{5}; // Default 5 second timeout
|
||||||
|
std::atomic<bool> interrupted{false};
|
||||||
|
|
||||||
NasalContext() {
|
NasalContext() {
|
||||||
vm_instance = std::make_unique<nasal::vm>();
|
vm_instance = std::make_unique<nasal::vm>();
|
||||||
|
vm_instance->set_interrupt_ptr(&interrupted);
|
||||||
|
}
|
||||||
|
|
||||||
|
~NasalContext() {
|
||||||
|
vm_instance.reset(); // Reset explicitly
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +78,9 @@ void* nasal_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void nasal_cleanup(void* context) {
|
void nasal_cleanup(void* context) {
|
||||||
delete static_cast<NasalContext*>(context);
|
auto* ctx = static_cast<NasalContext*>(context);
|
||||||
|
ctx->vm_instance.reset();
|
||||||
|
delete ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add new function to set timeout
|
// Add new function to set timeout
|
||||||
|
@ -148,6 +157,7 @@ const char* nasal_eval(void* context, const char* code, int show_time) {
|
||||||
// Wait for completion or timeout
|
// Wait for completion or timeout
|
||||||
auto status = future.wait_for(ctx->timeout);
|
auto status = future.wait_for(ctx->timeout);
|
||||||
if (status == std::future_status::timeout) {
|
if (status == std::future_status::timeout) {
|
||||||
|
ctx->interrupted.store(true);
|
||||||
std::remove(temp_filename);
|
std::remove(temp_filename);
|
||||||
throw std::runtime_error("Execution timed out after " +
|
throw std::runtime_error("Execution timed out after " +
|
||||||
std::to_string(ctx->timeout.count()) + " seconds");
|
std::to_string(ctx->timeout.count()) + " seconds");
|
||||||
|
|
Loading…
Reference in New Issue