Skip to content

Commit a6aa114

Browse files
committed
fix: ensure 'trap' keyword intercepts only panics occurring after its invocation. Allow pre-existing panic states to propagate when 'trap' is used in defer functions
1 parent b388c15 commit a6aa114

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

argon/vm/areval.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,9 @@ ArObject *argon::vm::Eval(Fiber *fiber) {
14251425
}
14261426
TARGET_OP(ST) {
14271427
cu_frame->trap_ptr = JUMPADDR(I32Arg(cu_frame->instr_ptr));
1428+
1429+
cu_frame->panic_baseline = (void *) fiber->panic;
1430+
14281431
DISPATCH4();
14291432
}
14301433
TARGET_OP(STATTR) {
@@ -1554,14 +1557,15 @@ ArObject *argon::vm::Eval(Fiber *fiber) {
15541557
}
15551558
TARGET_OP(TRAP) {
15561559
auto handler = I32Arg(cu_frame->instr_ptr);
1557-
ArObject *tmp = GetLastError();
1560+
ArObject *tmp = TrapPanic(fiber, cu_frame);
15581561

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

1561-
if (tmp == nullptr)
1562-
ret = (ArObject *) ResultNew(TOP(), true);
1563-
else
1564-
ret = (ArObject *) ResultNew(tmp, false);
1564+
if (handler == 0)
1565+
cu_frame->panic_baseline = nullptr;
1566+
1567+
ret = (ArObject *) (tmp == nullptr ? ResultNew(TOP(), true)
1568+
: ResultNew(tmp, false));
15651569

15661570
Release(tmp);
15671571

argon/vm/frame.h

+3
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ namespace argon::vm {
4242
/// Pointer to the code trap handler for this frame.
4343
unsigned char *trap_ptr;
4444

45+
/// Pointer to panic state(if any).
46+
void *panic_baseline;
47+
4548
/// Evaluation stack.
4649
datatype::ArObject **eval_stack;
4750

argon/vm/runtime.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,44 @@ ArObject *argon::vm::GetLastError() {
698698
return error;
699699
}
700700

701+
ArObject *argon::vm::TrapPanic(Fiber *fiber, const Frame *frame) {
702+
ArObject *error = nullptr;
703+
704+
struct Panic *expected = nullptr;
705+
706+
if (fiber == nullptr || frame == nullptr || fiber->panic == nullptr)
707+
return nullptr;
708+
709+
const auto *baseline = frame->panic_baseline;
710+
auto oom_check = false;
711+
712+
auto *tmp = fiber->panic;
713+
for (auto *cursor = fiber->panic; cursor != nullptr && cursor != baseline; cursor = tmp) {
714+
tmp = cursor->panic;
715+
716+
if (error == nullptr)
717+
error = cursor->object;
718+
719+
FrameDelRec(cursor->frame);
720+
721+
if (!oom_check) {
722+
if (panic_oom.compare_exchange_strong(expected, cursor)) {
723+
oom_check = true;
724+
continue;
725+
}
726+
}
727+
728+
memory::Free(cursor);
729+
}
730+
731+
if (tmp != nullptr)
732+
tmp->aborted = false;
733+
734+
fiber->panic = tmp;
735+
736+
return error;
737+
}
738+
701739
Future *argon::vm::EvalAsync(Context *context, datatype::Function *func, datatype::ArObject **argv,
702740
datatype::ArSize argc, argon::vm::OpCodeCallMode mode) {
703741
auto *fiber = AllocFiber(context);

argon/vm/runtime.h

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ namespace argon::vm {
3434

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

37+
argon::vm::datatype::ArObject *TrapPanic(Fiber *fiber, const Frame *frame);
38+
3739
argon::vm::datatype::Future *EvalAsync(Context *context,
3840
datatype::Function *func,
3941
datatype::ArObject **argv,

0 commit comments

Comments
 (0)