ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Devel-FindRef/FindRef.pm
Revision: 1.30
Committed: Fri May 16 07:43:52 2014 UTC (10 years ago) by root
Branch: MAIN
CVS Tags: rel-1_43
Changes since 1.29: +1 -1 lines
Log Message:
1.43

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