Subject: | Devel::Size SEGVs on XSUBs post 5.9.4 |
Date: | Thu, 17 Jun 2010 14:25:36 +0100 |
To: | bug-Devel-Size [...] rt.cpan.org |
From: | Nicholas Clark <nick [...] ccl4.org> |
Since perl 5.9.4 or so, CVs have shared the use of the same pointers for
XSUBs data and OP tree data , because a CV is either an XSUB or pure perl,
and never both. (see http://perl5.git.perl.org/perl.git/commit/d04ba5897acce642
and its 3 immediate parents)
Devel::Size currently doesn't cope with this, and assumes that CvSTART() and
CvROOT() are always valid, and always point to an optree. This causes
total_size() to SEGV on XSUBs, and constants, which are implemented as XSUBs.
The appended patch fixes this. Tested against 5.8.8, the 5.9.4 revision above,
and blead.
Nicholas Clark
--- Size.xs.orig 2008-08-24 10:24:04.000000000 +0100
+++ Size.xs 2010-06-17 14:21:08.000000000 +0100
@@ -11,6 +11,10 @@ static int fm_whine;
#define dbg_printf(x)
#endif
+#ifndef CvISXSUB
+# define CvISXSUB(cv) (CvXSUB(cv) ? TRUE : FALSE)
+#endif
+
#define carp puts
UV thing_size(SV *, HV *);
typedef enum {
@@ -543,11 +547,13 @@ UV thing_size(SV *orig_thing, HV *tracki
total_size += thing_size((SV *)CvOUTSIDE(thing), tracking_hash);
}
- if (check_new(tracking_hash, CvSTART(thing))) {
- total_size += op_size(CvSTART(thing), tracking_hash);
- }
- if (check_new(tracking_hash, CvROOT(thing))) {
- total_size += op_size(CvROOT(thing), tracking_hash);
+ if (!CvISXSUB(thing)) {
+ if (check_new(tracking_hash, CvSTART(thing))) {
+ total_size += op_size(CvSTART(thing), tracking_hash);
+ }
+ if (check_new(tracking_hash, CvROOT(thing))) {
+ total_size += op_size(CvROOT(thing), tracking_hash);
+ }
}
break;
--- t/basic.t.orig 2008-08-24 10:24:28.000000000 +0100
+++ t/basic.t 2010-06-17 14:19:47.000000000 +0100
@@ -8,7 +8,7 @@ my $tests;
BEGIN
{
chdir 't' if -d 't';
- plan tests => 12;
+ plan tests => 14;
use lib '../lib';
use lib '../blib/arch';
@@ -91,3 +91,9 @@ isnt (total_size(*foo), 0, 'total_size(*
my $code = sub { '1' };
isnt (total_size($code), 0, 'total_size($code) > 0');
+
+isnt (total_size(\&total_size), 0, 'total_size(\&total_size) > 0');
+
+use constant LARGE => 'N' x 4096;
+
+isnt (total_size(\&LARGE), 0, 'total_size for a constant > 0');