[interp] Fix filter clauses (#32192)
authormonojenkins <jo.shields+jenkins@xamarin.com>
Fri, 14 Feb 2020 22:40:09 +0000 (17:40 -0500)
committerGitHub <noreply@github.com>
Fri, 14 Feb 2020 22:40:09 +0000 (14:40 -0800)
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>
src/mono/mono/mini/interp/interp.c

index 97f031d..ad6f262 100644 (file)
@@ -7164,8 +7164,13 @@ exit_frame:
 
        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 */