GNU bug report logs - #21899
let/ec continuations not distinct under compiler

Previous Next

Package: guile;

Reported by: Zefram <zefram <at> fysh.org>

Date: Fri, 13 Nov 2015 07:59:02 UTC

Severity: normal

Done: Andy Wingo <wingo <at> pobox.com>

Bug is archived. No further changes may be made.

To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 21899 in the body.
You can then email your comments to 21899 AT debbugs.gnu.org in the normal way.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-guile <at> gnu.org:
bug#21899; Package guile. (Fri, 13 Nov 2015 07:59:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to Zefram <zefram <at> fysh.org>:
New bug report received and forwarded. Copy sent to bug-guile <at> gnu.org. (Fri, 13 Nov 2015 07:59:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Zefram <zefram <at> fysh.org>
To: bug-guile <at> gnu.org
Subject: let/ec continuations not distinct under compiler
Date: Fri, 13 Nov 2015 07:57:36 +0000
With guile 2.0.11:

scheme@(guile-user)> (use-modules (ice-9 control))
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (be 2)))))
$1 = (a (b 2))
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
$2 = (a (b 2))
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (ae 2))))
$3 = (a 2)

The middle of these three cases is wrong: it attempts to invoke the outer
escape continuation, but only goes as far as the target of the inner one,
which it isn't using.  It therefore produces the same result as the first
case, which invokes the inner escape continuation.  It ought to behave
like the third case, which shows that the outer escape continuation can
be successfully invoked when the unused inner continuation is not present.

The problem only affects let/ec, *not* call/ec:

scheme@(guile-user)> (list 'a (call/ec (lambda (ae) (list 'b (call/ec (lambda (be) (be 2)))))))
$4 = (a (b 2))
scheme@(guile-user)> (list 'a (call/ec (lambda (ae) (list 'b (call/ec (lambda (be) (ae 2)))))))
$5 = (a 2)
scheme@(guile-user)> (list 'a (call/ec (lambda (ae) (list 'b (ae 2)))))
$6 = (a 2)

It also only happens when compiling, not when interpreting:

scheme@(guile-user)> ,o interp #t
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (be 2)))))
$7 = (a (b 2))
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
$8 = (a 2)
scheme@(guile-user)> (list 'a (let/ec ae (list 'b (ae 2))))
$9 = (a 2)

-zefram




Information forwarded to bug-guile <at> gnu.org:
bug#21899; Package guile. (Fri, 24 Jun 2016 16:30:02 GMT) Full text and rfc822 format available.

Message #8 received at 21899 <at> debbugs.gnu.org (full text, mbox):

From: Andy Wingo <wingo <at> pobox.com>
To: Zefram <zefram <at> fysh.org>
Cc: 21899 <at> debbugs.gnu.org
Subject: Re: bug#21899: let/ec continuations not distinct under compiler
Date: Fri, 24 Jun 2016 18:29:26 +0200
On Fri 13 Nov 2015 08:57, Zefram <zefram <at> fysh.org> writes:

> With guile 2.0.11:
>
> scheme@(guile-user)> (use-modules (ice-9 control))
> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (be 2)))))
> $1 = (a (b 2))
> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
> $2 = (a (b 2))
> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (ae 2))))
> $3 = (a 2)
>
> The middle of these three cases is wrong: it attempts to invoke the outer
> escape continuation, but only goes as far as the target of the inner one,
> which it isn't using.  It therefore produces the same result as the first
> case, which invokes the inner escape continuation.  It ought to behave
> like the third case, which shows that the outer escape continuation can
> be successfully invoked when the unused inner continuation is not present.

This is a compiler bug in 2.0:

scheme@(guile-user)> ,optimize (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
$2 = (list 'a
      (let ((tag (list 'let/ec)))
        (call-with-prompt
          tag
          (lambda ()
            (list 'b
                  (let ((tag-1 tag))  ;; <<<< here is the bug
                    (call-with-prompt
                      tag-1
                      (lambda () (abort-to-prompt tag 2))
                      (lambda (_ . results) (@apply values results))))))
          (lambda (_ . results) (@apply values results)))))

In master:

scheme@(guile-user)> ,optimize (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
$1 = (list 'a
      (let ((tag (list 'let/ec)))
        (call-with-prompt
          tag
          (lambda ()
            (list 'b
                  (let ((tag-1 (list 'let/ec)))
                    (call-with-prompt
                      tag-1
                      (lambda () (apply abort tag 2 '()))
                      (lambda (_ . results) (apply values results))))))
          (lambda (_ . results) (apply values results)))))

Weird stuff!

Andy




Information forwarded to bug-guile <at> gnu.org:
bug#21899; Package guile. (Fri, 24 Jun 2016 16:49:02 GMT) Full text and rfc822 format available.

Message #11 received at 21899 <at> debbugs.gnu.org (full text, mbox):

From: Andy Wingo <wingo <at> pobox.com>
To: Zefram <zefram <at> fysh.org>
Cc: 21899 <at> debbugs.gnu.org
Subject: Re: bug#21899: let/ec continuations not distinct under compiler
Date: Fri, 24 Jun 2016 18:48:26 +0200
On Fri 24 Jun 2016 18:29, Andy Wingo <wingo <at> pobox.com> writes:

> On Fri 13 Nov 2015 08:57, Zefram <zefram <at> fysh.org> writes:
>
>> With guile 2.0.11:
>>
>> scheme@(guile-user)> (use-modules (ice-9 control))
>> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (be 2)))))
>> $1 = (a (b 2))
>> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
>> $2 = (a (b 2))
>> scheme@(guile-user)> (list 'a (let/ec ae (list 'b (ae 2))))
>> $3 = (a 2)
>>
>> The middle of these three cases is wrong: it attempts to invoke the outer
>> escape continuation, but only goes as far as the target of the inner one,
>> which it isn't using.  It therefore produces the same result as the first
>> case, which invokes the inner escape continuation.  It ought to behave
>> like the third case, which shows that the outer escape continuation can
>> be successfully invoked when the unused inner continuation is not present.
>
> This is a compiler bug in 2.0:
>
> scheme@(guile-user)> ,optimize (list 'a (let/ec ae (list 'b (let/ec be (ae 2)))))
> $2 = (list 'a
>       (let ((tag (list 'let/ec)))
>         (call-with-prompt
>           tag
>           (lambda ()
>             (list 'b
>                   (let ((tag-1 tag))  ;; <<<< here is the bug
>                     (call-with-prompt
>                       tag-1
>                       (lambda () (abort-to-prompt tag 2))
>                       (lambda (_ . results) (@apply values results))))))
>           (lambda (_ . results) (@apply values results)))))

Narrowed down:

  ,opt (let* ((x (list 'a))
              (y (list 'a)))
         (list x y))
  ;; ->
  (let* ((x (list 'a)) (y x)) (list x y))

It's a bug in 2.0's CSE pass somehow.

Andy




Information forwarded to bug-guile <at> gnu.org:
bug#21899; Package guile. (Fri, 24 Jun 2016 17:01:02 GMT) Full text and rfc822 format available.

Message #14 received at 21899 <at> debbugs.gnu.org (full text, mbox):

From: Zefram <zefram <at> fysh.org>
To: Andy Wingo <wingo <at> pobox.com>, 21899 <at> debbugs.gnu.org
Subject: Re: bug#21899: let/ec continuations not distinct under compiler
Date: Fri, 24 Jun 2016 18:00:38 +0100
Andy Wingo wrote:
>  ,opt (let* ((x (list 'a))
>              (y (list 'a)))
>         (list x y))
>  ;; ->
>  (let* ((x (list 'a)) (y x)) (list x y))

Wow, that's a scary level of wrongitude.  It's specific to let* (or
equivalent nested let forms), but really easy to trigger within that:

scheme@(guile-user)> (let ((x (list 'a)) (y (list 'a))) (eq? x y))
$1 = #f
scheme@(guile-user)> (let* ((x (list 'a)) (y (list 'a))) (eq? x y))
$2 = #t
scheme@(guile-user)> (let ((x (list 'a))) (let ((y (list 'a))) (eq? x y)))
$3 = #t

-zefram




Information forwarded to bug-guile <at> gnu.org:
bug#21899; Package guile. (Fri, 24 Jun 2016 17:12:01 GMT) Full text and rfc822 format available.

Message #17 received at 21899 <at> debbugs.gnu.org (full text, mbox):

From: Zefram <zefram <at> fysh.org>
To: Andy Wingo <wingo <at> pobox.com>, 21899 <at> debbugs.gnu.org
Subject: Re: bug#21899: let/ec continuations not distinct under compiler
Date: Fri, 24 Jun 2016 18:11:36 +0100
One more variant:

scheme@(guile-user)> (let ((x (list 'a))) (eq? x (list 'a)))
$1 = #t
scheme@(guile-user)> ,opt (let ((x (list 'a))) (eq? x (list 'a)))
$2 = (let ((x (list 'a))) (eq? x x))

-zefram




Reply sent to Andy Wingo <wingo <at> pobox.com>:
You have taken responsibility. (Fri, 24 Jun 2016 17:14:02 GMT) Full text and rfc822 format available.

Notification sent to Zefram <zefram <at> fysh.org>:
bug acknowledged by developer. (Fri, 24 Jun 2016 17:14:02 GMT) Full text and rfc822 format available.

Message #22 received at 21899-done <at> debbugs.gnu.org (full text, mbox):

From: Andy Wingo <wingo <at> pobox.com>
To: Zefram <zefram <at> fysh.org>
Cc: 21899-done <at> debbugs.gnu.org
Subject: Re: bug#21899: let/ec continuations not distinct under compiler
Date: Fri, 24 Jun 2016 19:13:01 +0200
[Message part 1 (text/plain, inline)]
On Fri 24 Jun 2016 19:00, Zefram <zefram <at> fysh.org> writes:

> Andy Wingo wrote:
>>  ,opt (let* ((x (list 'a))
>>              (y (list 'a)))
>>         (list x y))
>>  ;; ->
>>  (let* ((x (list 'a)) (y x)) (list x y))
>
> Wow, that's a scary level of wrongitude.

Indeed :/

Fixed in git with this patch:

[0001-Fix-bug-that-exposed-list-invocations-to-CSE.patch (text/plain, inline)]
From ea352d9e54793783a8272863748ea6d31b3f7295 Mon Sep 17 00:00:00 2001
From: Andy Wingo <wingo <at> pobox.com>
Date: Fri, 24 Jun 2016 19:03:36 +0200
Subject: [PATCH] Fix bug that exposed `list' invocations to CSE

* module/language/tree-il/effects.scm (make-effects-analyzer):
  Fix analysis for list, cons, make-prompt-tage, and vector; &allocation
  is a `cause' effect.  Fixes #21899.
* test-suite/tests/cse.test ("cse"): Add test case.
---
 module/language/tree-il/effects.scm | 8 ++++----
 test-suite/tests/cse.test           | 9 +++++++++
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/module/language/tree-il/effects.scm b/module/language/tree-il/effects.scm
index 1fe4aeb..6db4d47 100644
--- a/module/language/tree-il/effects.scm
+++ b/module/language/tree-il/effects.scm
@@ -278,16 +278,16 @@ of an expression."
           ;; Primitives that allocate memory.
           (($ <application> _ ($ <primitive-ref> _ 'cons) (x y))
            (logior (compute-effects x) (compute-effects y)
-                   &allocation))
+                   (cause &allocation)))
 
           (($ <application> _ ($ <primitive-ref> _ (or 'list 'vector)) args)
-           (logior (accumulate-effects args) &allocation))
+           (logior (accumulate-effects args) (cause &allocation)))
 
           (($ <application> _ ($ <primitive-ref> _ 'make-prompt-tag) ())
-           &allocation)
+           (cause &allocation))
 
           (($ <application> _ ($ <primitive-ref> _ 'make-prompt-tag) (arg))
-           (logior (compute-effects arg) &allocation))
+           (logior (compute-effects arg) (cause &allocation)))
 
           ;; Primitives that are normally effect-free, but which might
           ;; cause type checks, allocate memory, or access mutable
diff --git a/test-suite/tests/cse.test b/test-suite/tests/cse.test
index e0219e8..ca7dbc2 100644
--- a/test-suite/tests/cse.test
+++ b/test-suite/tests/cse.test
@@ -294,6 +294,15 @@
      (apply (primitive cons) (const 1) (const 2) (const 3))
      (const 4)))
 
+  ;; The (list 'a) does not propagate.
+  (pass-if-cse
+   (let* ((x (list 'a))
+          (y (list 'a)))
+     (list x y))
+   (let (x) (_) ((apply (primitive list) (const a)))
+        (let (y) (_) ((apply (primitive list) (const a)))
+             (apply (primitive list) (lexical x _) (lexical y _)))))
+
   (pass-if "http://bugs.gnu.org/12883"
     ;; In 2.0.6, compiling this code would trigger an out-of-bounds
     ;; vlist access in CSE's traversal of its "database".
-- 
2.8.3


bug archived. Request was from Debbugs Internal Request <help-debbugs <at> gnu.org> to internal_control <at> debbugs.gnu.org. (Sat, 23 Jul 2016 11:24:04 GMT) Full text and rfc822 format available.

This bug report was last modified 7 years and 277 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.