From ecc04bc9bb14bcd19481a96a9bfe23051ac06d86 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Wed, 11 Mar 2026 10:17:34 +0900 Subject: [PATCH 1/2] Implement DG_NEW and DG_STR_TO_METHOD instructions Used in Rance 9. --- src/vm.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/vm.c b/src/vm.c index 261d05a..daa7453 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2298,8 +2298,17 @@ static enum opcode execute_instruction(enum opcode opcode) } break; } - //case DG_NEW: - //case DG_STR_TO_METHOD: + case DG_NEW: { + stack_push(heap_alloc_page(alloc_page(DELEGATE_PAGE, 0, 0))); + break; + } + case DG_STR_TO_METHOD: { + stack_pop(); // delegate type index + int str = stack_pop().i; + stack_push(get_function_by_name(heap_get_string(str)->text)); + heap_unref(str); + break; + } // -- NOOPs --- case FUNC: break; From 197b89620c4b498a39c9823ca4e992366562d71e Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 15 Mar 2026 08:00:20 +0900 Subject: [PATCH 2/2] Fix extra heap_unref for ref arguments in delegate calls When a delegate finishes calling all registered functions, variable_fini() was called on the original stack arguments. For ref types, this results in an unbalanced heap_unref() because the caller pushes raw ref-values without incrementing the reference count. Non-ref string/struct/array arguments are not affected because their push instructions allocate new heap slots with ownership. This fixes use-after-free in T_Loop@checkSelect in Rance 9. --- src/vm.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/vm.c b/src/vm.c index daa7453..249f836 100644 --- a/src/vm.c +++ b/src/vm.c @@ -421,7 +421,15 @@ static void delegate_call(int dg_no, int return_address) stack_pop(); // dg_index stack_pop(); // dg_page for (int i = ain->delegates[dg_no].nr_variables - 1; i >= 0; i--) { - variable_fini(stack_pop(), ain->delegates[dg_no].variables[i].type.data, true); + union vm_value v = stack_pop(); + enum ain_data_type type = ain->delegates[dg_no].variables[i].type.data; + switch (type) { + case AIN_REF_TYPE: + break; + default: + variable_fini(v, type, true); + break; + } } if (return_values) { stack_push(r);