Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Junctions cause crash / infinite loop in &put and related routines and methods #6647

Closed
p6rt opened this issue Dec 8, 2017 · 7 comments
Closed

Comments

@p6rt
Copy link

p6rt commented Dec 8, 2017

Migrated from rt.perl.org#132549 (status was 'resolved')

Searchable as RT132549$

@p6rt
Copy link
Author

p6rt commented Dec 8, 2017

From @briandfoy

This comes from an answer to a Perl 6 question on Stackoverflow that
showed a different bug​:

  https://stackoverflow.com/q/45527881/2766176

With put() it does not and gives a strange error​:

  $ perl6 -e 'put any( 1, 3, 7 ) '
  This type cannot unbox to a native string​: P6opaque, Junction
  in block <unit> at -e line 1

  $ perl6 -e 'put( any( 1, 3, 7 ) )'
  This type cannot unbox to a native string​: P6opaque, Junction
  in block <unit> at -e line 1

With say it has no problem​:

  $ perl6 -e 'say any( 1, 3, 7 )'
  any(1, 3, 7)
  $ perl6 -e 'put any( 1, 3, 7 ).gist'
  any(1, 3, 7)

I'd expect anything that can .gist would be able to .Str.

This is Rakudo 2017.10 on macOS 10.13.

@p6rt
Copy link
Author

p6rt commented Dec 8, 2017

From @zoffixznet

On Fri, 08 Dec 2017 08​:28​:32 -0800, comdog wrote​:

This comes from an answer to a Perl 6 question on Stackoverflow that
showed a different bug​:

https://stackoverflow.com/q/45527881/2766176

With put() it does not and gives a strange error​:

I guess jnthn++ gets a score point for predicting[^1] this would happen​:

  <jnthn> Hmmm...not too keen on the Junction.Str patch
  <jnthn> Anything that (quite reasonably) does nqp​::unbox_s($foo.Str) is now
  going to (quite rightly) explode
  <timotimo> clearly we have to build UNBOXABLE_STR :)
  <jnthn> No, it can just explode, and then I'll point people at this commit. :P

If put() were made to work here, I'd expect it to junct and be equivalent to `put 1`, `put 3`, `put 7` executed in random order, but the OP in that SO has an entirely different expectation.

I'd expect anything that can .gist would be able to .Str.

Side note on that​: only the opposite is true. A basic class would .gist to its name, while its .Str would be an empty string accompanied by a warning. Also, some things, like self-referential structures or non-lazy infinite iterables, would take an infinite time to .Str, while getting .gisted is no trouble.

[1] https://irclog.perlgeek.de/perl6-dev/2017-08-09#i_14992203

@p6rt
Copy link
Author

p6rt commented Dec 8, 2017

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Dec 9, 2017

From @lizmat

On 8 Dec 2017, at 19​:21, Zoffix Znet via RT <perl6-bugs-followup@​perl.org> wrote​:

On Fri, 08 Dec 2017 08​:28​:32 -0800, comdog wrote​:

This comes from an answer to a Perl 6 question on Stackoverflow that
showed a different bug​:

https://stackoverflow.com/q/45527881/2766176

With put() it does not and gives a strange error​:

I guess jnthn++ gets a score point for predicting[^1] this would happen​:

<jnthn> Hmmm...not too keen on the Junction.Str patch
<jnthn> Anything that (quite reasonably) does nqp​::unbox_s($foo.Str) is now
going to (quite rightly) explode
<timotimo> clearly we have to build UNBOXABLE_STR :)
<jnthn> No, it can just explode, and then I'll point people at this commit. :P

Which would be me.

And as far as I recall atm, that was in response to making​:

  $ 6 'dd "foo" ~ any(1,3,5) ~ "bar"'
  any("foo1bar", "foo3bar", "foo5bar”)

work. If that shouldn’t work, or work differently, it can be ripped out / replaced. If that should work, then we need to look at fixing -put-.

If put() were made to work here, I'd expect it to junct and be equivalent to `put 1`, `put 3`, `put 7` executed in random order, but the OP in that SO has an entirely different expectation.

FWIW, I would also expect it to junct.

@p6rt
Copy link
Author

p6rt commented Dec 9, 2017

From @zoffixznet

On Sat, 09 Dec 2017 13​:19​:23 -0800, elizabeth wrote​:

If that shouldn’t work, or work differently, it can be ripped
out / replaced. If that should work, then we need to look at fixing
-put-.

IMO it should work, considering you can't nqp​::unbox_n/nqp​::unbox_i Junctions either, yet we don't have Junction-related explosions with numeric stuff.

I also found another issue​: IO​::Handle.print/put infiniloop in dispatch when given a Junction.

FWIW, I would also expect it to junct.

I started a fix down that path, but it kinda looks gross and dirty. Similar thing would be needed
in src/core/io_operators.pm for subroutine versions. The Junctions go through the **@​foo slurpy candidates
and the explosions then happen inside optimizations, where we assume x.Str gives an unboxable Str.

Is there a better way? Here's my thing​:

2017.11.50 zoffix@​VirtualBox~/CPANPRC/rakudo (master)$ gd

Inline Patch
diff --git a/src/core/IO/Handle.pm b/src/core/IO/Handle.pm
index 55ff911..0303047 100644
--- a/src/core/IO/Handle.pm
+++ b/src/core/IO/Handle.pm
@@ -652,6 +652,11 @@ my class IO::Handle {
     multi method print(IO::Handle:D: **@list is raw --> True) { # is raw gives List, which is cheaper
         self.print(@list.join);
     }
+    multi method print(IO::Handle:D: Junction \j --> True) {
+        # junct the Junction. Without this candidate, we'd go through the
+        # **@list slurpy candidate and dispatch infiniloop.
+        -> Any \el { self.print: el }(j)
+    }
 
     proto method put(|) {*}
     multi method put(IO::Handle:D: Str:D \x --> True) {
@@ -662,6 +667,11 @@ my class IO::Handle {
     multi method put(IO::Handle:D: **@list is raw --> True) { # is raw gives List, which is cheaper
         self.put(@list.join);
     }
+    multi method put(IO::Handle:D: Junction \j --> True) {
+        # junct the Junction. Without this candidate, we'd go through the
+        # **@list slurpy candidate and dispatch infiniloop.
+        -> Any \el { self.put: el }(j)
+    }
 
     multi method say(IO::Handle:D: Str:D $x --> True) {
         $!decoder or die X::IO::BinaryMode.new(:trying<say>);

@p6rt
Copy link
Author

p6rt commented Dec 14, 2017

From @zoffixznet

On Sat, 09 Dec 2017 15​:26​:25 -0800, cpan@​zoffix.com wrote​:

On Sat, 09 Dec 2017 13​:19​:23 -0800, elizabeth wrote​:

If that shouldn’t work, or work differently, it can be ripped
out / replaced. If that should work, then we need to look at fixing
-put-.

IMO it should work, considering you can't nqp​::unbox_n/nqp​::unbox_i
Junctions either, yet we don't have Junction-related explosions with
numeric stuff.

I also found another issue​: IO​::Handle.print/put infiniloop in
dispatch when given a Junction.

FWIW, I would also expect it to junct.

I started a fix down that path, but it kinda looks gross and dirty.
Similar thing would be needed
in src/core/io_operators.pm for subroutine versions. The Junctions go
through the **@​foo slurpy candidates
and the explosions then happen inside optimizations, where we assume
x.Str gives an unboxable Str.

Is there a better way? Here's my thing​:

2017.11.50 zoffix@​VirtualBox~/CPANPRC/rakudo (master)$ gd
diff --git a/src/core/IO/Handle.pm b/src/core/IO/Handle.pm
index 55ff911..0303047 100644
--- a/src/core/IO/Handle.pm
+++ b/src/core/IO/Handle.pm
@​@​ -652,6 +652,11 @​@​ my class IO​::Handle {
multi method print(IO​::Handle​:D​: **@​list is raw --> True) { # is
raw gives List, which is cheaper
self.print(@​list.join);
}
+ multi method print(IO​::Handle​:D​: Junction \j --> True) {
+ # junct the Junction. Without this candidate, we'd go through
the
+ # **@​list slurpy candidate and dispatch infiniloop.
+ -> Any \el { self.print​: el }(j)
+ }

proto method put(|) {*}
multi method put(IO​::Handle​:D​: Str​:D \x --> True) {
@​@​ -662,6 +667,11 @​@​ my class IO​::Handle {
multi method put(IO​::Handle​:D​: **@​list is raw --> True) { # is raw
gives List, which is cheaper
self.put(@​list.join);
}
+ multi method put(IO​::Handle​:D​: Junction \j --> True) {
+ # junct the Junction. Without this candidate, we'd go through
the
+ # **@​list slurpy candidate and dispatch infiniloop.
+ -> Any \el { self.put​: el }(j)
+ }

multi method say(IO​::Handle​:D​: Str​:D $x --> True) {
$!decoder or die X​::IO​::BinaryMode.new(​:trying<say>);

Thank you for the report. lizmat++ fixed this.

Fix​: rakudo/rakudo@8155c4b885
  rakudo/rakudo@9de4a60efe
  rakudo/rakudo@07616effd1
Test​: Raku/roast@97ceb93f40214cb7c

@p6rt
Copy link
Author

p6rt commented Dec 14, 2017

@zoffixznet - Status changed from 'open' to 'resolved'

@p6rt p6rt closed this as completed Dec 14, 2017
@lizmat lizmat changed the title Junctions cause crash / inifnite loop in &put and related routines and methods Junctions cause crash / infinite loop in &put and related routines and methods Jan 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant