When executing a filter we create a new interp frame, that is a duplicate of the original frame that contains the filter. Once the execution of the filter is finished, we were copying the stack contents back to the base frame. The problem with this is that when the filter is run, the stack is not completely unwinded, meaning that later we can still run a finally block in a frame called by the base frame. This finally block can access the stack arguments, which would reside on the stack of base frame. This means that we must not override the stack of the base frame, only the locals.
Fixes some tests from System.Linq.Expressions suite.
Co-authored-by: Vlad Brezae <brezaevlad@gmail.com>
g_assert (frame->imethod);
- if (clause_args && clause_args->base_frame)
- memcpy (clause_args->base_frame->stack, frame->stack, frame->imethod->alloca_size);
+ if (clause_args && clause_args->base_frame) {
+ // We finished executing a filter. The execution stack of the base frame
+ // should remain unmodified, but we need to update the local space.
+ char *locals_base = (char*)clause_args->base_frame->stack + frame->imethod->stack_size + frame->imethod->vt_stack_size;
+
+ memcpy (locals_base, locals, frame->imethod->locals_size);
+ }
if (!clause_args && frame->parent && frame->parent->state.ip) {
/* Return to the main loop after a non-recursive interpreter call */