Skip Menu |

Preferred bug tracker

Please visit the preferred bug tracker to report your issue.

This queue is for tickets about the Throwable CPAN distribution.

Report information
The Basics
Id: 85708
Status: open
Priority: 0/
Queue: Throwable

People
Owner: Nobody in particular
Requestors: djerius [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: Involuntary stringification of $@ in previous_exception
My exception class overloads "", and I noticed that its stringification function was being called unexpectedly. The following code sets the stage: package E1 { use Carp 'cluck'; use Moo; with 'Throwable'; use overload '""' => sub { cluck ("stringify ", $_[0]->text) }; has text => ( is => 'ro' ); } eval { # set up $@ eval { E1->throw( text => 1 ) }; # this will cause the default code for previous_exception to # access $Throwable::_HORRIBLE_HACK{ERROR}, which will trigger # stringification E1->throw( text => 2 ); }; And here is the output: stringify 1 at throw line 8. E1::__ANON__('E1=HASH(0xe4f9c8)', undef, '') called at (eval 13) line 34 E1::new(undef, 'text', 2) called at /home/dj/.perlbrew/libs/perl-5.16.2@dev/lib/perl5/Throwable.pm line 38 Throwable::throw('E1', 'text', 2) called at throw line 16 eval {...} called at throw line 14 $ perl throw stringify 1 at throw line 8. E1::__ANON__('E1=HASH(0x2397a08)', undef, '') called at (eval 13) line 34 E1::new(undef, 'text', 2) called at /home/dj/.perlbrew/libs/perl-5.16.2@dev/lib/perl5/Throwable.pm line 38 Throwable::throw('E1', 'text', 2) called at throw line 20 eval {...} called at throw line 13 With appropriate instrumentation one finds that the stringification occurs at line 18 in Throwable.pm: 15 has 'previous_exception' => ( 16 is => 'ro', 17 default => Sub::Quote::quote_sub(q< 18 if ($Throwable::_HORRIBLE_HACK{ERROR}) { 19 $Throwable::_HORRIBLE_HACK{ERROR} 20 } elsif (defined $@ and (ref $@ or length $@)) { 21 $@; 22 } else { 23 undef; 24 } 25 >), 26 ); Replacing the conditional with something more like that in line 20: 15 has 'previous_exception' => ( 16 is => 'ro', 17 default => Sub::Quote::quote_sub(q< 18 my $e; 19 if (defined( $e = $Throwable::_HORRIBLE_HACK{ERROR}) 20 && ( ref $e || $e ) ) { 21 $e; 22 } elsif (defined $@ and (ref $@ or length $@)) { 23 $@; 24 } else { 25 undef; 26 } 27 >), 28 ); should(!?) replicate the logic of the original conditional without triggering stringification. (Well, it passes the tests and it doesn't cause my test code to cluck). The copy to $e might appear to be a bit less efficient, but benchmarking between that and using $Throwable::_HORRIBLE_HACK{ERROR} directly didn't seem to make a difference. (I benchmarked the above code; had $@ been some longish string and not a reference, perhaps that might actually make using $Throwable::_HORRIBLE_HACK{ERROR} directly more efficient.) Patch attached. Thanks, Diab
Subject: Throwable-0.200008.patch
# This is a patch for Throwable-0.200008.orig to update it to Throwable-0.200008 # # To apply this patch: # STEP 1: Chdir to the source directory. # STEP 2: Run the 'applypatch' program with this patch file as input. # # If you do not have 'applypatch', it is part of the 'makepatch' package # that you can fetch from the Comprehensive Perl Archive Network: # http://www.perl.com/CPAN/authors/Johan_Vromans/makepatch-x.y.tar.gz # In the above URL, 'x' should be 2 or higher. # # To apply this patch without the use of 'applypatch': # STEP 1: Chdir to the source directory. # STEP 2: Run the 'patch' program with this file as input. # #### End of Preamble #### #### Patch data follows #### diff -c 'Throwable-0.200008.orig/lib/Throwable.pm' 'Throwable-0.200008/lib/Throwable.pm' Index: ./lib/Throwable.pm *** ./lib/Throwable.pm Tue Apr 30 12:50:22 2013 --- ./lib/Throwable.pm Wed May 29 13:01:22 2013 *************** *** 15,22 **** has 'previous_exception' => ( is => 'ro', default => Sub::Quote::quote_sub(q< ! if ($Throwable::_HORRIBLE_HACK{ERROR}) { ! $Throwable::_HORRIBLE_HACK{ERROR} } elsif (defined $@ and (ref $@ or length $@)) { $@; } else { --- 15,24 ---- has 'previous_exception' => ( is => 'ro', default => Sub::Quote::quote_sub(q< ! my $e; ! if (defined( $e = $Throwable::_HORRIBLE_HACK{ERROR}) ! && ( ref $e || $e ) ) { ! $e; } elsif (defined $@ and (ref $@ or length $@)) { $@; } else { #### End of Patch data #### #### ApplyPatch data follows #### # Data version : 1.0 # Date generated : Wed May 29 13:06:47 2013 # Generated by : makepatch 2.05 # Recurse directories : Yes # Excluded files : (\A|/).*\~\Z # (\A|/).*\.a\Z # (\A|/).*\.bak\Z # (\A|/).*\.BAK\Z # (\A|/).*\.elc\Z # (\A|/).*\.exe\Z # (\A|/).*\.gz\Z # (\A|/).*\.ln\Z # (\A|/).*\.o\Z # (\A|/).*\.obj\Z # (\A|/).*\.olb\Z # (\A|/).*\.old\Z # (\A|/).*\.orig\Z # (\A|/).*\.rej\Z # (\A|/).*\.so\Z # (\A|/).*\.Z\Z # (\A|/)\.del\-.*\Z # (\A|/)\.make\.state\Z # (\A|/)\.nse_depinfo\Z # (\A|/)core\Z # (\A|/)tags\Z # (\A|/)TAGS\Z # p 'lib/Throwable.pm' 2212 1369846882 0100644 #### End of ApplyPatch data #### #### End of Patch kit [created: Wed May 29 13:06:47 2013] #### #### Patch checksum: 59 2078 60654 #### #### Checksum: 77 2780 53097 ####
I think that checking definedness of the hash entry is probably sufficient..? I'll start with that. -- rjbs