X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=t%2Flib%2FDBICTest%2FUtil%2FLeakTracer.pm;h=58790e4332e554294e1df777d7a00ee0808b03f9;hb=de4705b7393350ae7cde8f5409f204747c1a4a4e;hp=f3cf859e5cee12b7df3999118439400ed2fc91b7;hpb=556c4fe6aae477e7f9c9d910316dd2132787593f;p=dbsrgits%2FDBIx-Class.git diff --git a/t/lib/DBICTest/Util/LeakTracer.pm b/t/lib/DBICTest/Util/LeakTracer.pm index f3cf859..58790e4 100644 --- a/t/lib/DBICTest/Util/LeakTracer.pm +++ b/t/lib/DBICTest/Util/LeakTracer.pm @@ -5,23 +5,22 @@ use strict; use Carp; use Scalar::Util qw(isweak weaken blessed reftype); -use DBIx::Class::_Util 'refcount'; +use DBIx::Class::_Util qw(refcount hrefaddr); use DBIx::Class::Optional::Dependencies; use Data::Dumper::Concise; use DBICTest::Util 'stacktrace'; use constant { CV_TRACING => DBIx::Class::Optional::Dependencies->req_ok_for ('test_leaks_heavy'), + SKIP_SCALAR_REFS => ( $] > 5.017 ) ? 1 : 0, }; use base 'Exporter'; -our @EXPORT_OK = qw(populate_weakregistry assert_empty_weakregistry hrefaddr); +our @EXPORT_OK = qw(populate_weakregistry assert_empty_weakregistry visit_refs); my $refs_traced = 0; my $leaks_found = 0; my %reg_of_regs; -sub hrefaddr { sprintf '0x%x', &Scalar::Util::refaddr } - # so we don't trigger stringification sub _describe_ref { sprintf '%s%s(%s)', @@ -53,6 +52,10 @@ sub populate_weakregistry { for keys %$reg; } + # FIXME/INVESTIGATE - something fishy is going on with refs to plain + # strings, perhaps something to do with the CoW work etc... + return $target if SKIP_SCALAR_REFS and reftype($target) eq 'SCALAR'; + if (! defined $weak_registry->{$refaddr}{weakref}) { $weak_registry->{$refaddr} = { stacktrace => stacktrace(1), @@ -112,30 +115,43 @@ sub visit_refs { next unless length ref $r; + # no diving into weakregistries + next if $reg_of_regs{hrefaddr $r}; + next if $args->{seen_refs}{my $dec_addr = Scalar::Util::refaddr($r)}++; $visited_cnt++; $args->{action}->($r) or next; - my $type = reftype $r; - if ($type eq 'HASH') { - $visited_cnt += visit_refs({ %$args, refs => [ map { - ( !isweak($r->{$_}) ) ? $r->{$_} : () - } keys %$r ] }); - } - elsif ($type eq 'ARRAY') { - $visited_cnt += visit_refs({ %$args, refs => [ map { - ( !isweak($r->[$_]) ) ? $r->[$_] : () - } 0..$#$r ] }); - } - elsif ($type eq 'REF' and !isweak($$r)) { - $visited_cnt += visit_refs({ %$args, refs => [ $$r ] }); - } - elsif (CV_TRACING and $type eq 'CODE') { - $visited_cnt += visit_refs({ %$args, refs => [ map { - ( !isweak($_) ) ? $_ : () - } scalar PadWalker::closed_over($r) ] }); # scalar due to RT#92269 - } + # This may end up being necessarry some day, but do not slow things + # down for now + #if ( defined( my $t = tied($r) ) ) { + # $visited_cnt += visit_refs({ %$args, refs => [ $t ] }); + #} + + local $@; + eval { + my $type = reftype $r; + if ($type eq 'HASH') { + $visited_cnt += visit_refs({ %$args, refs => [ map { + ( !isweak($r->{$_}) ) ? $r->{$_} : () + } keys %$r ] }); + } + elsif ($type eq 'ARRAY') { + $visited_cnt += visit_refs({ %$args, refs => [ map { + ( !isweak($r->[$_]) ) ? $r->[$_] : () + } 0..$#$r ] }); + } + elsif ($type eq 'REF' and !isweak($$r)) { + $visited_cnt += visit_refs({ %$args, refs => [ $$r ] }); + } + elsif (CV_TRACING and $type eq 'CODE') { + $visited_cnt += visit_refs({ %$args, refs => [ map { + ( !isweak($_) ) ? $_ : () + } scalar PadWalker::closed_over($r) ] }); # scalar due to RT#92269 + } + 1; + } or warn "Could not descend into @{[ _describe_ref($r) ]}: $@\n"; } $visited_cnt; } @@ -150,6 +166,9 @@ sub assert_empty_weakregistry { croak 'Expecting a registry hashref' unless ref $weak_registry eq 'HASH'; + defined $weak_registry->{$_}{weakref} or delete $weak_registry->{$_} + for keys %$weak_registry; + return unless keys %$weak_registry; my $tb = eval { Test::Builder->new } @@ -223,7 +242,7 @@ sub assert_empty_weakregistry { next if ! defined $weak_registry->{$addr}{weakref}; - $leaks_found++; + $leaks_found++ unless $tb->in_todo; $tb->ok (0, "Leaked $weak_registry->{$addr}{display_name}"); my $diag = do { @@ -239,6 +258,9 @@ sub assert_empty_weakregistry { ; }; + # FIXME - need to add a circular reference seeker based on the visitor + # (will need a bunch of modifications, punting with just a stub for now) + $diag .= Devel::FindRef::track ($weak_registry->{$addr}{weakref}, 50) . "\n" if ( $ENV{TEST_VERBOSE} && eval { require Devel::FindRef }); @@ -249,9 +271,22 @@ sub assert_empty_weakregistry { } $tb->diag($diag); + +# if ($leaks_found == 1) { +# # using the fh dumper due to intermittent buffering issues +# # in case we decide to exit soon after (possibly via _exit) +# require Devel::MAT::Dumper; +# local $Devel::MAT::Dumper::MAX_STRING = -1; +# open( my $fh, '>:raw', "leaked_${addr}_pid$$.pmat" ) or die $!; +# Devel::MAT::Dumper::dumpfh( $fh ); +# close ($fh) or die $!; +# +# use POSIX; +# POSIX::_exit(1); +# } } - if (! $quiet and ! $leaks_found) { + if (! $quiet and !$leaks_found and ! $tb->in_todo) { $tb->ok(1, sprintf "No leaks found at %s line %d", (caller())[1,2] ); } }