ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Devel-FindRef/FindRef.pm
Revision: 1.27
Committed: Thu Apr 5 05:11:14 2012 UTC (12 years, 1 month ago) by root
Branch: MAIN
Changes since 1.26: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

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