Skip Menu |

This queue is for tickets about the Moo CPAN distribution.

Report information
The Basics
Id: 95960
Status: resolved
Priority: 0/
Queue: Moo

People
Owner: Nobody in particular
Requestors: KENTNL [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in:
  • 1.004005
  • 1.004_003
  • 1.004_004
Fixed in: 1.004006



Subject: utf8 triggers "Malformed UTF8 Character" warning from attribute generator (CoreBug?)

This issue started with 1.004_003 but I didn't see it till 1.004005 hit the shelves.

Its really weird and very much likely a P5P bug, but the triviality of it basically means "utf8 + Moo + builder => 1 + require in builder" is almost certian to fail somewhere.

Attached is the failing code that is currently failing on 5.20-RC1 with Moo 1.004005

There's a lot of weird things happening, like, for instance, loading "Foo" into memory trigger the bug, even if it doesn't appear in the code path.

And for instance, removing the "require Bar" statement from the builder method of Foo.pm also suppresses the bug.

The original incarnation of this bug involved multiple files, but its replicatable without multiple files simply using `eval` and $INC{} instead.

Subject: stacktrace.txt
Subject: t.pl
#!/usr/bin/env perl use strict; use warnings; my $have_foo = 1; my $test_foo = 0; my $have_bar = 0; $have_foo and eval <<'_PKG_FOO'; use strict; use warnings; use utf8; # this package must use utf8 to trigger the bug package Foo; use Moo; has 'bar' => ( is => 'ro', lazy => 1, builder => 1 ); sub _build_bar { require Bar; # require must be called inside the builder to trigger the bug return Bar->new(); } $INC{'Foo.pm'} = 1; _PKG_FOO $have_bar and eval <<'_PKG_BAR'; use strict; use warnings; package Bar; use Moo; has 'quux' => ( is => 'ro', lazy => 1, builder => 1); sub _build_quux { my ( $self, ) = @_; return 1; # never gets this far }; $INC{'Bar.pm'} = 1; _PKG_BAR # Oddly, these *both* trigger the bug, regardless # ... but only as long as both Foo and Bar are declared. # # have_foo = 0 , test_foo = 0, have_bar = 1 # no warnings # have_foo = 1 , test_foo = 0, have_bar = 1 # warnings from bar # have_foo = 1 , test_foo = 1, have_bar = 1 # warnings from bar and foo $have_foo and $test_foo and do { my $x = Foo->new(); $x->bar->quux; }; $have_bar and do { my $y = Bar->new(); $y->quux; };
Er, have_foo and have_bar both need to be == 1 to see the failure.
Subject: t.pl
#!/usr/bin/env perl use strict; use warnings; my $have_foo = 1; my $test_foo = 1; my $have_bar = 1; $have_foo and eval <<'_PKG_FOO'; use strict; use warnings; use utf8; # this package must use utf8 to trigger the bug package Foo; use Moo; has 'bar' => ( is => 'ro', lazy => 1, builder => 1 ); sub _build_bar { require Bar; # require must be called inside the builder to trigger the bug return Bar->new(); } $INC{'Foo.pm'} = 1; _PKG_FOO $have_bar and eval <<'_PKG_BAR'; use strict; use warnings; package Bar; use Moo; has 'quux' => ( is => 'ro', lazy => 1, builder => 1); sub _build_quux { my ( $self, ) = @_; return 1; # never gets this far }; $INC{'Bar.pm'} = 1; _PKG_BAR # Oddly, these *both* trigger the bug, regardless # ... but only as long as both Foo and Bar are declared. # # have_foo = 0 , test_foo = 0, have_bar = 1 # no warnings # have_foo = 1 , test_foo = 0, have_bar = 1 # warnings from bar # have_foo = 1 , test_foo = 1, have_bar = 1 # warnings from bar and foo $have_foo and $test_foo and do { my $x = Foo->new(); $x->bar->quux; }; $have_bar and do { my $y = Bar->new(); $y->quux; };
And an actual stacktrace instead of a blank file is nice.
Subject: stacktrace.txt
Sorry. Failing at shell this morning.
Subject: stacktrace.txt

Message body is not shown because it is too large.

After screwing around with the Moo test suite, I discovered a much simpler example:

 

perl -Mutf8 t/method-generate-accessor.t

And reducing futher gives:

---
{
 
  my ($code, $cap) = $gen->generate_isa_check('attr', '$value',
    quote_sub q{ die "bad value: $_[0]" unless $_[0] && $_[0] == 5 });
  my $value = 4;
  {
    use utf8;
    eval $code;
  }
  like $@, qr/bad value: 4/, 'isa from quoted sub code works';
  is_deeply $cap, {}, 'isa from quoted sub has no captures';
}
---

As another way to create the problem.

It doesn't explain why its happening where its happening, I suspect some kind of spooky weird scope blead happening, but this looks like the core issue.

Somehow the 'eval $code' is evaling non-utf8-safe code in a utf-8 context.

 

This is resolved in 1.004006