~ chicken-core (chicken-5) 3e0f640ecf22f6be7af1947b875132415556ca5b


commit 3e0f640ecf22f6be7af1947b875132415556ca5b
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Mon Apr 8 12:34:52 2019 +0200
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Mon Apr 8 12:34:52 2019 +0200

    Revert "Make `call/cc` continuations behave like `values` ones."
    
    This reverts commit 2dc0c5929abc398f1d344500fba9fc10ed4857cc.
    
    The approach didn't work because generated continuations do not
    perform argument count checking and will unsafely access their
    argvectors in positions that may not be there.  When doing a GC this
    will break because save_and_reclaim is called with slots at
    uninitialised memory locations.  Fixes #1601.

diff --git a/NEWS b/NEWS
index 2c73ebd8..5e8a133a 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,10 @@
 - Runtime system
   - Removed the unused, undocumented (and incorrect!) C functions
     C_delete_symbol_table and C_set_symbol_table.
+  - Continuations which discard additional values beyond the first no
+    longer accept multiple values via direct invocation after being
+    captured through `call/cc`, only via `values` (revert of #1390,
+    due to #1601)
 
 - Module system
   - When you try to import the module you are currently defining into
diff --git a/runtime.c b/runtime.c
index b8bccb75..c06b5432 100644
--- a/runtime.c
+++ b/runtime.c
@@ -546,6 +546,7 @@ static void set_profile_timer(C_uword freq);
 static void take_profile_sample();
 
 static C_cpsproc(call_cc_wrapper) C_noret;
+static C_cpsproc(call_cc_values_wrapper) C_noret;
 static C_cpsproc(gc_2) C_noret;
 static C_cpsproc(allocate_vector_2) C_noret;
 static C_cpsproc(generic_trampoline) C_noret;
@@ -877,7 +878,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
 {
   /* IMPORTANT: hardcoded table size -
      this must match the number of C_pte calls + 1 (NULL terminator)! */
-  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 62);
+  C_PTABLE_ENTRY *pt = (C_PTABLE_ENTRY *)C_malloc(sizeof(C_PTABLE_ENTRY) * 63);
   int i = 0;
 
   if(pt == NULL)
@@ -886,6 +887,7 @@ static C_PTABLE_ENTRY *create_initial_ptable()
   C_pte(termination_continuation);
   C_pte(callback_return_continuation);
   C_pte(values_continuation);
+  C_pte(call_cc_values_wrapper);
   C_pte(call_cc_wrapper);
   C_pte(C_gc);
   C_pte(C_allocate_vector);
@@ -7048,7 +7050,10 @@ void C_ccall C_call_cc(C_word c, C_word *av)
   if(C_immediatep(cont) || C_header_bits(cont) != C_CLOSURE_TYPE)
     barf(C_BAD_ARGUMENT_TYPE_ERROR, "call-with-current-continuation", cont);
   
-  wrapper = C_closure(&a, 2, (C_word)call_cc_wrapper, k);
+  /* Check for values-continuation: */
+  if(C_block_item(k, 0) == (C_word)values_continuation)
+    wrapper = C_closure(&a, 2, (C_word)call_cc_values_wrapper, k);
+  else wrapper = C_closure(&a, 2, (C_word)call_cc_wrapper, k);
   
   av2[ 0 ] = cont;
   av2[ 1 ] = k;
@@ -7062,11 +7067,28 @@ void C_ccall call_cc_wrapper(C_word c, C_word *av)
   C_word
     closure = av[ 0 ],
     /* av[ 1 ] is current k and ignored */
+    result,
     k = C_block_item(closure, 1);
+
+  if(c != 3) C_bad_argc(c, 3);
+
+  result = av[ 2 ];
+  C_kontinue(k, result);
+}
+
+
+void C_ccall call_cc_values_wrapper(C_word c, C_word *av)
+{
+  C_word
+    closure = av[ 0 ],
+    /* av[ 1 ] is current k and ignored */
+    k = C_block_item(closure, 1),
+    x1,
+    n = c;
   
   av[ 0 ] = k;               /* reuse av */
-  C_memmove(av + 1, av + 2, (c - 1) * sizeof(C_word));
-  C_do_apply(c - 1, av);
+  C_memmove(av + 1, av + 2, (n - 1) * sizeof(C_word));
+  C_do_apply(n - 1, av);
 }
 
 
Trap