# New Ticket Created by  Bob Rogers 
# Please include the string:  [perl #56458]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=56458 >


   Every RetContinuation in the active call chain must be promoted to a
full Continuation by the act of taking an explicit continuation, lest
the RetContinuation recycle the context on return when we can still
return to it afterwards.  For some reason, this does not happen in the
particular test case added by the attached patch.  However, I have been
unable to fix it, because the obvious fix (also in the patch) breaks the
build (in r28794) rather horribly.  So, I'm submitting this ticket for
the record, and will continue working on it when I have more time.  (If
somebody wants to find out for which revision this last worked, that
would be a big help.  It's possible that this has never worked; I tend
to doubt it, but don't bother going back more than three years.)

                                        -- Bob Rogers
                                           http://rgrjr.dyndns.org/

* t/pmc/exception.t:
   + Test case to expose a problem with RetContinuation promotion.
* src/pmc/continuation.pmc:
   + This is the obvious fix, but it breaks the build.

Diffs between last version checked in and current workfile(s):

Index: t/pmc/exception.t
===================================================================
--- t/pmc/exception.t   (revision 28798)
+++ t/pmc/exception.t   (working copy)
@@ -6,7 +6,7 @@
 use warnings;
 use lib qw( . lib ../lib ../../lib );
 use Test::More;
-use Parrot::Test tests => 35;
+use Parrot::Test tests => 36;
 
 =head1 NAME
 
@@ -836,6 +836,68 @@
 ok 3
 OUTPUT
 
+pir_output_is(<<'CODE', <<'OUTPUT', "taking a continuation promotes RetCs");
+## This test creates a continuation in a inner sub and re-invokes it later.  
The
+## re-invocation signals an error, which is caught by an intermediate sub.
+## Returning from the "test" sub the second time failed in r28794; invoking
+## parrot with "-D80" shows clearly that the "test" context was being recycled
+## prematurely.  For some reason, it is necessary to signal the error in order
+## to expose the bug.
+.sub main :main
+       .local int redux
+       .local pmc cont
+       ## debug 0x80
+       redux = 0
+       print "calling test\n"
+       cont = test()
+       print "back from test\n"
+       if redux goto done
+       redux = 1
+       print "calling cont\n"
+       cont()
+       print "never.\n"
+done:
+       print "done.\n"
+.end
+.sub test
+       ## Push a handler around the foo() call.
+       push_eh handle_errs
+       print "  calling foo\n"
+       .local pmc cont
+       cont = foo()
+       pop_eh
+       print "  returning from test.\n"
+       .return (cont)
+handle_errs:
+       print "  test:  caught error\n"
+       .return (cont)
+.end
+.sub foo
+       ## Take a continuation.
+       .local pmc cont
+       cont = new 'Continuation'
+       set_addr cont, over_there 
+       print "    returning from foo\n"
+       .return (cont)
+over_there:
+       print "    got over there.\n"
+       .local pmc ex
+       ex = new 'Exception'
+       throw ex
+.end
+CODE
+calling test
+  calling foo
+    returning from foo
+  returning from test.
+back from test
+calling cont
+    got over there.
+  test:  caught error
+back from test
+done.
+OUTPUT
+
 # Local Variables:
 #   mode: cperl
 #   cperl-indent-level: 4
Index: src/pmc/continuation.pmc
===================================================================
--- src/pmc/continuation.pmc    (revision 28798)
+++ src/pmc/continuation.pmc    (working copy)
@@ -178,7 +178,18 @@
     VTABLE void set_pointer(void *value) {
         opcode_t    * const pos = (opcode_t *)value;
         Parrot_cont * const cc  = PMC_cont(SELF);
+        parrot_context_t * const to_ctx  = cc->to_ctx;
+        PMC         * const current_cont = to_ctx->current_cont;
 
+        /*
+         * Whenever we capture a continuation, all return continuations
+         * up the call chain may be reused due to invoking the
+         * continuation. To avoid that all return continuations are
+         * converted to true continuations.
+         */
+        if (current_cont)
+            invalidate_retc_context(INTERP, current_cont);
+
         if (cc->dynamic_state)
             cc->dynamic_state->refcount--;
 

End of diffs.

Reply via email to