mauke / Function-Parameters

Function::Parameters - define functions and methods with parameter lists ("subroutine signatures")
https://metacpan.org/pod/Function::Parameters
18 stars 19 forks source link

Devel::Cover hangs when used with Function::Parameters #29

Closed sdt closed 7 years ago

sdt commented 7 years ago

My test scripts hang when I run them with Devel::Cover. I narrowed it down to Function::Parameters.

I have a minimal test case here: https://github.com/sdt/devel-cover-function-parameters-hang

This code is enough to reproduce the hang:

fun double($x) {
    return add($x, $x);
}

fun add($x, $y) {
    return $x + $y;
}

Re-ordering those so that add is defined before double makes the problem go away. Setting the runtime flag also makes the problem go away (but causes other errors).

This has already been reported at https://github.com/pjcj/Devel--Cover/issues/164 - I've added this test case to that bug as well.

mauke commented 7 years ago

Can be further reduced to:

perl -e 'use Devel::Cover; use Function::Parameters; sub f1 { f2() } fun f2(@) { }'
mauke commented 7 years ago

Further reduced to:

perl -d -e 'use Function::Parameters; sub f1 { f2() } fun f2(@) { }'

I.e. this is not a bug in Devel::Cover, it's a bug in Function::Parameters.

mauke commented 7 years ago

Further reduced to:

perl -e '\&f2; sub f2 { sub f2; eval "" }'

That means it's a core perl bug (RT #131146). :-(

sdt commented 7 years ago

2.000004-TRIAL confirmed working for me with 5.24.0

Great stuff, thanks so much @mauke !

zmughal commented 7 years ago

I have another example that causes Perl to hang with Function::Parameters combined with Type::Tiny under Devel::Cover:

#!perl

# perlbrew exec bash -c 'cpanm -qn Devel::Cover Function::Parameters Types::Standard && rm -Rf cover_db && ( timeout 10 perl dc-fp-tt-hang.pl || echo "coverage timeout" )'

# Adding Devel::Cover causes it to hang.
use Devel::Cover -silent => 1;

use Types::Standard qw(Str);
use Function::Parameters;

# Adding type constraint causes it to hang under Devel::Cover
fun f( Str $x ) {
    print "$x\n";
}

f("done");

Tested under different perls here.

The issue is still there under Function::Parameters@2.000004-TRIAL.

mauke commented 7 years ago

The other issue is unrelated (both to the original problem (which hangs during compilation) and to Function::Parameters, apparently). I was able to reduce it to:

#!perl
use Devel::Cover -silent => 1;

use Types::Standard qw(Str);
use constant MyType => Str;

sub f {
    return MyType if @_;
}

I think this is related to perl -MO=Deparse also looping forever on the above program but that can be worked around by using perl -MO=Deparse,-d.

What's going on is that Function::Parameters inlines type constraint objects into the function prologue it generates. You can get the same effect without XS shenanigans by using named constants (perl inlines them automatically). Type::Tiny objects are self-referential (they contain a (possibly weak?) reference back to themselves). When B::Deparse encounters a constant value in the optree, it has to dump it. By default it uses its own built-in function, which doesn't handle cycles, so it loops forever. The -d switch tells it to use Data::Dumper instead, which handles cycles. (I've reported this as https://rt.perl.org/Ticket/Display.html?id=131148.)

I'm not familiar with the internals of Devel::Cover, though. Maybe it's doing something similar?

sdt commented 7 years ago

2.000005-TRIAL also works for me.

mauke commented 7 years ago

I've put a workaround for the perl 5.22/5.24 core bug into 2.000006.