Devel--Cover
Devel--Cover copied to clipboard
Devel::Cover interfers with Scope Guards
use strict;
use warnings;
{
my $scope;
BEGIN {
require Scope::Guard;
$scope = Scope::Guard::scope_guard(sub { print "scope clean\n"; });
print "End of scope creator\n";
}
print "End of guarded scope\n";
} # Should harvest here
print "Beginning of new scope\n";
END {
print "End of program\n";
}
# Scope harvests here
Without Devel::Cover, the above code does:
End of scope creator
End of guarded scope
scope clean
Beginning of new scope
End of program
With Devel::Cover, the above code does:
End of scope creator
End of guarded scope
Beginning of new scope
End of program
scope clean
Ouch, my mistake, this seems to be a general problem of the perl debugger ! :(. perl -d:Confess
is enough to trigger this.
Ok, weeded out the logic that trips into fails on -d
and -d:Confess
. However, still have one test case that works on both of those, and still fails on -MDevel::Cover
use strict;
use warnings;
BEGIN {
package Foo;
sub DESTROY {
$_[0]->[0]->();
}
}
sub safely {
my ($var) = @_;
return bless [ sub { print "$var\n"} ], 'Foo';
}
{
my $scope;
BEGIN {
$scope = safely("Destruction");
print "End of scope creator\n";
}
print "End of guarded scope\n";
}
print "Beginning of new scope\n";
END {
print "End of program\n";
}
Further whittled the problem down to appearing somewhere in XS.
Putting FAIL=1 in ENV makes instance destruction wait till GlobalDestruction
use strict;
use warnings;
BEGIN {
package Devel::Cover;
use strict;
use warnings;
use DynaLoader ();
our @ISA = "DynaLoader";
if ( $ENV{"FAIL"} ) {
bootstrap Devel::Cover;
}
}
BEGIN {
package Foo;
sub DESTROY {
$_[0]->[0]->();
}
}
sub safely {
my ($var) = @_;
return bless [ sub { print "$var\n" } ], 'Foo';
}
{
my $scope;
BEGIN {
$scope = safely("Destruction");
print "End of scope creator\n";
}
print "End of guarded scope\n";
}
print "Beginning of new scope\n";
END {
print "End of program\n";
}
Digging down to the roots, the smallest blob of XS that replicates this behaviour is this:
#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
MODULE = Devel::Cover PACKAGE = Devel::Cover
BOOT:
{
MY_CXT_INIT;
#if PERL_VERSION > 6
PL_savebegin = TRUE;
#endif
}
Seems PL_savebegin breaks things :/
Thanks for doing so much to track this down!
The PL_savebegin being set is to be able to get coverage of BEGIN blocks. But yes, this is going to affect behaviour so it's not a good solution.
What I really need (I think!) is a hook that gets called just before a block is destroyed. This would also solve other problems where coverage cannot be collected at the moment.
The opfreehook branch is work in this direction, but it's not there yet.