Skip to content

Commit

Permalink
fix: ensure 'trap' keyword intercepts only panics occurring after its…
Browse files Browse the repository at this point in the history
… invocation. Allow pre-existing panic states to propagate when 'trap' is used in defer functions
  • Loading branch information
jacopodl committed Aug 13, 2024
1 parent b388c15 commit a6aa114
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 5 deletions.
14 changes: 9 additions & 5 deletions argon/vm/areval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,6 +1425,9 @@ ArObject *argon::vm::Eval(Fiber *fiber) {
}
TARGET_OP(ST) {
cu_frame->trap_ptr = JUMPADDR(I32Arg(cu_frame->instr_ptr));

cu_frame->panic_baseline = (void *) fiber->panic;

DISPATCH4();
}
TARGET_OP(STATTR) {
Expand Down Expand Up @@ -1554,14 +1557,15 @@ ArObject *argon::vm::Eval(Fiber *fiber) {
}
TARGET_OP(TRAP) {
auto handler = I32Arg(cu_frame->instr_ptr);
ArObject *tmp = GetLastError();
ArObject *tmp = TrapPanic(fiber, cu_frame);

cu_frame->trap_ptr = handler > 0 ? JUMPADDR(handler) : nullptr;

if (tmp == nullptr)
ret = (ArObject *) ResultNew(TOP(), true);
else
ret = (ArObject *) ResultNew(tmp, false);
if (handler == 0)
cu_frame->panic_baseline = nullptr;

ret = (ArObject *) (tmp == nullptr ? ResultNew(TOP(), true)
: ResultNew(tmp, false));

Release(tmp);

Expand Down
3 changes: 3 additions & 0 deletions argon/vm/frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ namespace argon::vm {
/// Pointer to the code trap handler for this frame.
unsigned char *trap_ptr;

/// Pointer to panic state(if any).
void *panic_baseline;

/// Evaluation stack.
datatype::ArObject **eval_stack;

Expand Down
38 changes: 38 additions & 0 deletions argon/vm/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,44 @@ ArObject *argon::vm::GetLastError() {
return error;
}

ArObject *argon::vm::TrapPanic(Fiber *fiber, const Frame *frame) {
ArObject *error = nullptr;

struct Panic *expected = nullptr;

if (fiber == nullptr || frame == nullptr || fiber->panic == nullptr)
return nullptr;

const auto *baseline = frame->panic_baseline;
auto oom_check = false;

auto *tmp = fiber->panic;
for (auto *cursor = fiber->panic; cursor != nullptr && cursor != baseline; cursor = tmp) {
tmp = cursor->panic;

if (error == nullptr)
error = cursor->object;

FrameDelRec(cursor->frame);

if (!oom_check) {
if (panic_oom.compare_exchange_strong(expected, cursor)) {
oom_check = true;
continue;
}
}

memory::Free(cursor);
}

if (tmp != nullptr)
tmp->aborted = false;

fiber->panic = tmp;

return error;
}

Future *argon::vm::EvalAsync(Context *context, datatype::Function *func, datatype::ArObject **argv,
datatype::ArSize argc, argon::vm::OpCodeCallMode mode) {
auto *fiber = AllocFiber(context);
Expand Down
2 changes: 2 additions & 0 deletions argon/vm/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ namespace argon::vm {

argon::vm::datatype::ArObject *GetLastError();

argon::vm::datatype::ArObject *TrapPanic(Fiber *fiber, const Frame *frame);

argon::vm::datatype::Future *EvalAsync(Context *context,
datatype::Function *func,
datatype::ArObject **argv,
Expand Down

0 comments on commit a6aa114

Please sign in to comment.