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

> IMHO the most likely approach is to trigger error handling. In case you define your own sub prior to loading the module, Perl should throw a "redefined" warning and you can intercept that via $SIG{__WARN__} -handler. I would try that.

I tried my best.

I was capable to intercept the warning, but it doesn't seem like it's even possible to redefine a constant. (or to be more precise: the once stored constant can't be changed)°

Other may have more success:

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

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

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

update

°) not sure what is going wrong here, maybe it's a timimg issue

Replies are listed 'Best First'.
Re^3: How to redefine a modules private function?
by LanX (Saint) on Mar 09, 2022 at 00:25 UTC
    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

      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