/usr/lib/perl5/Devel/FindRef.pm is in libdevel-findref-perl 1.422-1build3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | package Devel::FindRef;
use common::sense;
use XSLoader;
use Scalar::Util;
BEGIN {
our $VERSION = '1.422';
XSLoader::load __PACKAGE__, $VERSION;
}
=head1 NAME
Devel::FindRef - where is that reference to my variable hiding?
=head1 SYNOPSIS
use Devel::FindRef;
print Devel::FindRef::track \$some_variable;
=head1 DESCRIPTION
Tracking down reference problems (e.g. you expect some object to be
destroyed, but there are still references to it that keep it alive) can be
very hard. Fortunately, perl keeps track of all its values, so tracking
references "backwards" is usually possible.
The C<track> function can help track down some of those references back to
the variables containing them.
For example, for this fragment:
package Test;
use Devel::FindRef;
use Scalar::Util;
our $var = "hi\n";
my $global_my = \$var;
our %global_hash = (ukukey => \$var);
our $global_hashref = { ukukey2 => \$var };
sub testsub {
my $testsub_local = $global_hashref;
print Devel::FindRef::track \$var;
}
my $closure = sub {
my $closure_var = \$_[0];
Scalar::Util::weaken (my $weak_ref = \$var);
testsub;
};
$closure->($var);
The output is as follows (or similar to this, in case I forget to update
the manpage after some changes):
SCALAR(0x7cc888) [refcount 6] is
+- referenced by REF(0x8abcc8) [refcount 1], which is
| in the lexical '$closure_var' in CODE(0x8abc50) [refcount 4], which is
| +- the closure created at tst:18.
| +- referenced by REF(0x7d3c58) [refcount 1], which is
| | in the lexical '$closure' in CODE(0x7ae530) [refcount 2], which is
| | +- the containing scope for CODE(0x8ab430) [refcount 3], which is
| | | in the global &Test::testsub.
| | +- the main body of the program.
| +- in the lexical '&' in CODE(0x7ae530) [refcount 2], which was seen before.
+- referenced by REF(0x7cc7c8) [refcount 1], which is
| in the lexical '$global_my' in CODE(0x7ae530) [refcount 2], which was seen before.
+- in the global $Test::var.
+- referenced by REF(0x7cc558) [refcount 1], which is
| in the member 'ukukey2' of HASH(0x7ae140) [refcount 2], which is
| +- referenced by REF(0x8abad0) [refcount 1], which is
| | in the lexical '$testsub_local' in CODE(0x8ab430) [refcount 3], which was seen before.
| +- referenced by REF(0x8ab4f0) [refcount 1], which is
| in the global $Test::global_hashref.
+- referenced by REF(0x7ae518) [refcount 1], which is
| in the member 'ukukey' of HASH(0x7d3bb0) [refcount 1], which is
| in the global %Test::global_hash.
+- referenced by REF(0x7ae2f0) [refcount 1], which is
a temporary on the stack.
It is a bit convoluted to read, but basically it says that the value
stored in C<$var> is referenced by:
=over 4
=item - the lexical C<$closure_var> (0x8abcc8), which is inside an instantiated
closure, which in turn is used quite a bit.
=item - the package-level lexical C<$global_my>.
=item - the global package variable named C<$Test::var>.
=item - the hash element C<ukukey2>, in the hash in the my variable
C<$testsub_local> in the sub C<Test::testsub> and also in the hash
C<$referenced by Test::hash2>.
=item - the hash element with key C<ukukey> in the hash stored in
C<%Test::hash>.
=item - some anonymous mortalised reference on the stack (which is caused
by calling C<track> with the expression C<\$var>, which creates the
reference).
=back
And all these account for six reference counts.
=head1 EXPORTS
None.
=head1 FUNCTIONS
=over 4
=item $string = Devel::FindRef::track $ref[, $depth]
Track the perl value pointed to by C<$ref> up to a depth of C<$depth> and
return a descriptive string. C<$ref> can point at any perl value, be it
anonymous sub, hash, array, scalar etc.
This is the function you most often use.
=cut
sub find($);
sub _f($) {
"$_[0] [refcount " . (_refcnt $_[0]) . "]"
}
sub track {
my ($ref, $depth) = @_;
@_ = ();
my $buf = "";
my %seen;
Scalar::Util::weaken $ref;
my $track; $track = sub {
my ($refref, $depth, $indent) = @_;
if ($depth) {
my (@about) = find $$refref;
if (@about) {
for my $about (@about) {
$about->[0] =~ s/([^\x20-\x7e])/sprintf "\\{%02x}", ord $1/ge;
$buf .= "$indent" . (@about > 1 ? "+- " : "") . $about->[0];
if (@$about > 1) {
if ($seen{ref2ptr $about->[1]}++) {
$buf .= " " . (_f $about->[1]) . ", which was seen before.\n";
} else {
$buf .= " " . (_f $about->[1]) . ", which is\n";
$track->(\$about->[1], $depth - 1, $about == $about[-1] ? "$indent " : "$indent| ");
}
} else {
$buf .= ".\n";
}
}
} else {
$buf .= "$indent not found anywhere I looked :(\n";
}
} else {
$buf .= "$indent not referenced within the search depth.\n";
}
};
$buf .= (_f $ref) . " is\n";
$track->(\$ref, $depth || $ENV{PERL_DEVEL_FINDREF_DEPTH} || 10, "");
$buf
}
=item @references = Devel::FindRef::find $ref
Return arrayrefs that contain [$message, $ref] pairs. The message
describes what kind of reference was found and the C<$ref> is the
reference itself, which can be omitted if C<find> decided to end the
search. The returned references are all weak references.
The C<track> function uses this to find references to the value you are
interested in and recurses on the returned references.
=cut
sub find($) {
my ($about, $excl) = &find_;
my %excl = map +($_ => undef), @$excl;
grep !($#$_ && exists $excl{ref2ptr $_->[1]}), @$about
}
=item $ref = Devel::FindRef::ptr2ref $integer
Sometimes you know (from debugging output) the address of a perl scalar
you are interested in (e.g. C<HASH(0x176ff70)>). This function can be used
to turn the address into a reference to that scalar. It is quite safe to
call on valid addresses, but extremely dangerous to call on invalid ones.
# we know that HASH(0x176ff70) exists, so turn it into a hashref:
my $ref_to_hash = Devel::FindRef::ptr2ref 0x176ff70;
=item $ref = Devel::FindRef::ref2ptr $reference
The opposite of C<ptr2ref>, above: returns the internal address of the
value pointed to by the passed reference. I<No checks whatsoever will be
done>, so don't use this.
=back
=head1 ENVIRONMENT VARIABLES
You can set the environment variable C<PERL_DEVEL_FINDREF_DEPTH> to an
integer to override the default depth in C<track>. If a call explicitly
specified a depth it is not overridden.
=head1 AUTHOR
Marc Lehmann <pcg@goof.com>.
=head1 COPYRIGHT AND LICENSE
Copyright (C) 2007, 2008 by Marc Lehmann.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.8 or,
at your option, any later version of Perl 5 you may have available.
=cut
1
|