From: Abigail Date: Sat, 20 Feb 2010 17:55:06 +0000 (+0100) Subject: Don't recurse forever if both new() and TIESCALAR() are missing. X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=bc3707112523ba7a72c27d7ae60ac3cca3ffbad1;p=p5sagit%2Fp5-mst-13.2.git Don't recurse forever if both new() and TIESCALAR() are missing. This should fix issue #72878. Before calling $pkg -> new in TIESCALAR, we check whether $pkg -> new is actually the new defined in the Tie::Scalar package; if true, croak instead of calling it. --- diff --git a/lib/Tie/Scalar.pm b/lib/Tie/Scalar.pm index 8048569..329770a 100644 --- a/lib/Tie/Scalar.pm +++ b/lib/Tie/Scalar.pm @@ -104,9 +104,20 @@ sub new { sub TIESCALAR { my $pkg = shift; - if ($pkg->can('new') and $pkg ne __PACKAGE__) { - warnings::warnif("WARNING: calling ${pkg}->new since ${pkg}->TIESCALAR is missing"); - $pkg->new(@_); + my $pkg_new = $pkg -> can ('new'); + + if ($pkg_new and $pkg ne __PACKAGE__) { + my $my_new = __PACKAGE__ -> can ('new'); + if ($pkg_new == $my_new) { + # + # Prevent recursion + # + croak "$pkg must define either a TIESCALAR() or a new() method"; + } + + warnings::warnif ("WARNING: calling ${pkg}->new since " . + "${pkg}->TIESCALAR is missing"); + $pkg -> new (@_); } else { croak "$pkg doesn't define a TIESCALAR method"; diff --git a/lib/Tie/Scalar.t b/lib/Tie/Scalar.t index 3c5d9b6..fb33ca1 100644 --- a/lib/Tie/Scalar.t +++ b/lib/Tie/Scalar.t @@ -17,7 +17,7 @@ sub new { 'Fooled you.' } package main; use vars qw( $flag ); -use Test::More tests => 13; +use Test::More tests => 16; use_ok( 'Tie::Scalar' ); @@ -74,3 +74,37 @@ sub new { sub DESTROY { $main::flag = 1; } + + +# +# Bug #72878: don't recurse forever if both new and TIESCALAR are missing. +# +package main; + +@NoMethods::ISA = qw [Tie::Scalar]; + +eval {tie my $foo => "NoMethods"}; + +like $@ => + qr /\QNoMethods must define either a TIESCALAR() or a new() method/, + "croaks if both new() and TIESCALAR() are missing"; + +# +# Don't croak on missing new/TIESCALAR if you're inheriting one. +# +my $called1 = 0; +my $called2 = 0; + +sub HasMethod1::new {$called1 ++} + @HasMethod1::ISA = qw [Tie::Scalar]; + @InheritHasMethod1::ISA = qw [HasMethod1]; + +sub HasMethod2::TIESCALAR {$called2 ++} + @HasMethod2::ISA = qw [Tie::Scalar]; + @InheritHasMethod2::ISA = qw [HasMethod2]; + +my $r1 = eval {tie my $foo => "InheritHasMethod1"; 1}; +my $r2 = eval {tie my $foo => "InheritHasMethod2"; 1}; + +ok $r1 && $called1, "inheriting new() does not croak"; +ok $r2 && $called2, "inheriting TIESCALAR() does not croak";