From f04f0ac1603775cd882912e9204d7543b477628a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Kochma=C5=84ski?= Date: Wed, 27 Aug 2025 09:49:21 +0200 Subject: [PATCH] bytevm: fix a possible segmentation fault in OP_PUSHKEYS The issue was revealed by registering long (EQL LIST) elements as cons types -- essentially we've reached the frame size limit in the middle of the loop, the frame was resized, but the pointer `first' was relative to the old frame base. The solution is to reinitialize the pointer before each iteration. --- src/c/interpreter.d | 32 +++++++++++++++++--------------- src/c/stacks.d | 1 - 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/c/interpreter.d b/src/c/interpreter.d index 90f9631eb..1f21d4c2a 100644 --- a/src/c/interpreter.d +++ b/src/c/interpreter.d @@ -653,12 +653,10 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes) Checks the stack frame for keyword arguments. */ CASE(OP_PUSHKEYS); { - cl_object keys_list, aok, *first, *last; - cl_index count; + cl_object keys_list, aok, *ptr, *end; + cl_index count, limit; GET_DATA(keys_list, vector, data); - first = ECL_STACK_FRAME_PTR(frame) + frame_index; - count = frame->frame.size - frame_index; - last = first + count; + limit = count = frame->frame.size - frame_index; if (ecl_unlikely(count & 1)) { VEbad_lambda_odd_keys(bytecodes, frame); } @@ -667,28 +665,32 @@ ecl_interpret(cl_object frame, cl_object closure, cl_object bytecodes) cl_object name = ECL_CONS_CAR(keys_list); cl_object flag = ECL_NIL; cl_object value = ECL_NIL; - cl_object *p = first; - for (; p != last; ++p) { - if (*(p++) == name) { + ptr = ECL_STACK_FRAME_PTR(frame) + frame_index; + end = ptr + limit; + for (; ptr != end; ptr++) { + if (*(ptr++) == name) { count -= 2; if (flag == ECL_NIL) { flag = ECL_T; - value = *p; + value = *ptr; } } } + /* Pushing to the stack may resize it, so be careful to reinitialize + pointers using the new value of ECL_STACK_FRAME_PTR. */ if (flag != ECL_NIL) ECL_STACK_PUSH(the_env, value); ECL_STACK_PUSH(the_env, flag); } if (count && Null(aok)) { - cl_object *p = first; - for (; p != last; ++p) { - if (*(p++) == @':allow-other-keys') { - aok = *p; + ptr = ECL_STACK_FRAME_PTR(frame) + frame_index; + end = ptr + limit; + for (; ptr != end; ptr++) { + if (*(ptr++) == @':allow-other-keys') { + aok = *ptr; count -= 2; /* only the first :allow-other-keys argument is considered */ - for (++p; p != last; ++p) { - if (*(p++) != @':allow-other-keys') + for (ptr++; ptr != end; ptr++) { + if (*(ptr++) != @':allow-other-keys') break; count -= 2; } diff --git a/src/c/stacks.d b/src/c/stacks.d index d37f63e3b..119f03106 100644 --- a/src/c/stacks.d +++ b/src/c/stacks.d @@ -392,7 +392,6 @@ ecl_bds_overflow(void) cl_env_ptr env = ecl_process_env(); cl_index margin = ecl_option_values[ECL_OPT_BIND_STACK_SAFETY_AREA]; cl_index size = env->bds_stack.size; - cl_index limit_size = env->bds_stack.limit_size; ecl_bds_ptr org = env->bds_stack.org; ecl_bds_ptr last = org + size; if (env->bds_stack.limit >= last) {