use B ();
use Carp 'croak';
use Storable 'nfreeze';
-use Scalar::Util qw(weaken blessed reftype);
+use Scalar::Util qw(weaken blessed reftype refaddr);
use List::Util qw(first);
use Sub::Quote qw(qsub quote_sub);
our @EXPORT_OK = qw(
sigwarn_silencer modver_gt_or_eq modver_gt_or_eq_and_lt
fail_on_internal_wantarray fail_on_internal_call
- refdesc refcount hrefaddr is_exception
+ refdesc refcount hrefaddr is_exception detected_reinvoked_destructor
quote_sub qsub perlstring serialize deep_clone
UNRESOLVABLE_CONDITION
);
sub perlstring ($) { q{"}. quotemeta( shift ). q{"} };
-sub hrefaddr ($) { sprintf '0x%x', &Scalar::Util::refaddr||0 }
+sub hrefaddr ($) { sprintf '0x%x', &refaddr||0 }
sub refdesc ($) {
croak "Expecting a reference" if ! length ref $_[0];
sprintf '%s%s(0x%x)',
( defined( $_[1] = blessed $_[0]) ? "$_[1]=" : '' ),
reftype $_[0],
- Scalar::Util::refaddr($_[0]),
+ refaddr($_[0]),
;
}
return $not_blank;
}
+{
+ my $destruction_registry = {};
+
+ sub CLONE {
+ $destruction_registry = { map
+ { defined $_ ? ( refaddr($_) => $_ ) : () }
+ values %$destruction_registry
+ };
+ }
+
+ # This is almost invariably invoked from within DESTROY
+ # throwing exceptions won't work
+ sub detected_reinvoked_destructor {
+
+ # quick "garbage collection" pass - prevents the registry
+ # from slowly growing with a bunch of undef-valued keys
+ defined $destruction_registry->{$_} or delete $destruction_registry->{$_}
+ for keys %$destruction_registry;
+
+ if (! length ref $_[0]) {
+ printf STDERR '%s() expects a blessed reference %s',
+ (caller(0))[3],
+ Carp::longmess,
+ ;
+ return undef; # don't know wtf to do
+ }
+ elsif (! defined $destruction_registry->{ my $addr = refaddr($_[0]) } ) {
+ weaken( $destruction_registry->{$addr} = $_[0] );
+ return 0;
+ }
+ else {
+ carp_unique ( sprintf (
+ 'Preventing *MULTIPLE* DESTROY() invocations on %s - an *EXTREMELY '
+ . 'DANGEROUS* condition which is *ALMOST CERTAINLY GLOBAL* within your '
+ . 'application, affecting *ALL* classes without active protection against '
+ . 'this. Diagnose and fix the root cause ASAP!!!%s',
+ refdesc $_[0],
+ ( ( $INC{'Devel/StackTrace.pm'} and ! do { local $@; eval { Devel::StackTrace->VERSION(2) } } )
+ ? " (likely culprit Devel::StackTrace\@@{[ Devel::StackTrace->VERSION ]} found in %INC, http://is.gd/D_ST_refcap)"
+ : ''
+ )
+ ));
+
+ return 1;
+ }
+ }
+}
+
sub modver_gt_or_eq ($$) {
my ($mod, $ver) = @_;