in reply to Re^2: How to redefine a modules private function?
in thread How to redefine a modules private function?

OK I'm seeing clearer now.

1. my code was wrong in that part

package ALIEN; no warnings "redefine"; sub DOMAIN_PORT() { 666 }

it's better written as

no warnings "redefine"; *ALIEN::DOMAIN_PORT = sub() { 666 };

2. But this creates a weird error

Attempt to free unreferenced scalar: SV 0x6917d8, Perl interpreter: 0x767b98 at d:/tmp/pm/patch_constant.pl line 41.

Which is most likely explained by %SIG

__DIE__/__WARN__ handlers are very special in one respect: they may be called to report (probable) errors found by the parser. In such a case the parser may be in inconsistent state, so any attempt to evaluate Perl code from such a handler will probably result in a segfault. This means that warnings or errors that result from parsing Perl should be used with extreme caution, like this:

bottom line

nice idea, but no luck :/

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re^4: How to redefine a modules private function?
by LanX (Saint) on Mar 09, 2022 at 13:30 UTC
    To wrap things up: it works and it doesn't.

    The following code runs without errors.

    Problem is that the handler is actually called before the redefinition happens. Which means the successful change of the constant (from "Dummy" to 666) is reversed again to 53 ...

    use strict; use warnings; use Data::Dump qw/pp dd/; $|=1; BEGIN { $\="\n"; my $old = $SIG{__WARN__}; my $new_constant = sub() { 666 }; *ALIEN::DOMAIN_PORT_NEW = sub() { 666 }; $SIG{__WARN__} = sub { my ( $msg ) = @_ ; if ($msg =~ /Constant subroutine DOMAIN_PORT redefined/ ) { $SIG{__WARN__} = $old; print "REDEFINED", pp caller; print ALIEN::DOMAIN_PORT(); no warnings "redefine"; *ALIEN::DOMAIN_PORT_OLD = *ALIEN::DOMAIN_PORT; *ALIEN::DOMAIN_PORT = *ALIEN::DOMAIN_PORT_NEW; print ALIEN::DOMAIN_PORT(); } }; *ALIEN::DOMAIN_PORT = sub () {"DUMMY"}; } package ALIEN; sub DOMAIN_PORT() { 53 } BEGIN { print "pre compile"; } sub test { print "Inside test: ", DOMAIN_PORT; } test();

    REDEFINED("main", "d:/tmp/pm/patch_constant.pl", 39) DUMMY 666 pre compile Inside test: 53

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

      But hooking into a later sub like a() actually works.

      But this kind of patching requires that the code never changes, tho it's arguably safer than a source-filter in disguise.

      use strict; use warnings; use Data::Dump qw/pp dd/; $|=1; my $DBG; BEGIN { $DBG=0; $\="\n"; my $old = $SIG{__WARN__}; $SIG{__WARN__} = sub { my ( $msg ) = @_ ; if ($msg =~ /Constant subroutine a redefined/ ) { $SIG{__WARN__} = $old; print "REDEFINED", pp caller if $DBG; no warnings 'redefine'; *ALIEN::DOMAIN_PORT = sub() { 666 }; } }; *ALIEN::a = sub () {"DUMMY"}; # cause redefine warning } # used package package ALIEN; # ---8<---- snippet from AnyEvent::DNS sub DOMAIN_PORT() { 53 } sub resolver (); sub a($$) { my ($domain, $cb) = @_; resolver->resolve ($domain => "a", sub { $cb->(map $_->[4], @_); }); } # --->8---- snippet from AnyEvent::DNS BEGIN { print "pre compile" if $DBG; } sub test { print "Inside test: ", DOMAIN_PORT; } test();

      Inside test: 666

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery