Subject: | 'use base' should not be used in packages with several subpackages defined |
We have been debugging a very rarely occurring bug with Net::DNS v1.12 and v1.13 and perl v5.20.
*** FATAL PROGRAM ERROR!! Unknown instance method 'rcode'
*** which the program has attempted to call for the object:
***
. IN OPT
***
*** THIS IS A BUG IN THE CALLING SOFTWARE, which incorrectly assumes
*** that the object would be of a particular type. The type of an
*** object should be checked before calling any of its methods.
***
Attempt to reload Net/DNS/RR/OPT.pm aborted.
Compilation failed in require at (eval 172) line 2.
Net::DNS::RR 1569 at /opt/OSAGperlm/lib/Net/DNS/Header.pm line 172.
Net::DNS::Header::rcode(Net::DNS::Header=REF(0x32d9580), "FORMERR") called at /opt/OSAGperlm/lib/Net/DNS/Packet.pm line 273
Net::DNS::Packet::reply(Net::DNS::Packet=HASH(0x3eadff8)) called at /opt/OSAGperlm/lib/Net/DNS/Nameserver.pm line 193
Net::DNS::Nameserver::make_reply(Net::DNS::Nameserver=HASH(0x2ce2410), Net::DNS::Packet=HASH(0x3eadff8), "127.0.0.1", HASH(0x35eca50)) called at /opt/OSAGperlm/lib/Net/DNS/Nameserver.pm line 410
Net::DNS::Nameserver::udp_connection(Net::DNS::Nameserver=HASH(0x2ce2410), IO::Socket::INET=GLOB(0x3eb5d08)) called at /opt/OSAGperlm/lib/Net/DNS/Nameserver.pm line 464
Net::DNS::Nameserver::loop_once(Net::DNS::Nameserver=HASH(0x2ce2410), 10) called at /opt/OSAGperlm/lib/Net/DNS/Nameserver.pm line 541
We have been able to track the bug down to the following:
1) Net/DNS/RR/OPT.pm and Net/DNS/DomainName.pm declares several packages in the same file and is using "use base" to load the parent class (which is in the same file).
2) Our program does daemonize and change its GID/UID to a user which is not able to read the current working directory.
3) This triggers a side effect of "use base" which will fail as the current working directory is not readable when requiring Net::DNS::RR::OPT::DHU which is actually in OPT.pm which has already been loaded.
The fix is to use either a newer version of perl which does not automatically include the current working directory in the @INC or to use "use parent -norequire" instead of use base. This is described here: http://perldoc.perl.org/parent.html
The attached patch does exactly does, it will use 'use parent -norequire' for all packages which have the parent in the same .pm file declared. We have been fixing a similar issue in libwww-perl recently: https://github.com/libwww-perl/libwww-perl/pull/259/files
Please let me know if you need further information on this.
Subject: | Net-DNS-v1.13.patch |
diff -ur Net-DNS-1.13/lib/Net/DNS/DomainName.pm Net-DNS-1.13-patched/lib/Net/DNS/DomainName.pm
--- Net-DNS-1.13/lib/Net/DNS/DomainName.pm 2017-10-18 11:00:36.000000000 +0200
+++ Net-DNS-1.13-patched/lib/Net/DNS/DomainName.pm 2017-11-21 15:39:51.000000000 +0100
@@ -155,7 +155,7 @@
########################################
package Net::DNS::DomainName1035;
-use base qw(Net::DNS::DomainName);
+use parent -norequire, qw(Net::DNS::DomainName);
=head1 Net::DNS::DomainName1035
@@ -217,7 +217,7 @@
########################################
package Net::DNS::DomainName2535;
-use base qw(Net::DNS::DomainName);
+use parent -norequire, qw(Net::DNS::DomainName);
=head1 Net::DNS::DomainName2535
diff -ur Net-DNS-1.13/lib/Net/DNS/RR/OPT.pm Net-DNS-1.13-patched/lib/Net/DNS/RR/OPT.pm
--- Net-DNS-1.13/lib/Net/DNS/RR/OPT.pm 2017-10-18 11:00:36.000000000 +0200
+++ Net-DNS-1.13-patched/lib/Net/DNS/RR/OPT.pm 2017-11-21 15:38:33.000000000 +0100
@@ -230,10 +230,10 @@
package Net::DNS::RR::OPT::DHU; # RFC6975
-use base qw(Net::DNS::RR::OPT::DAU);
+use parent -norequire, qw(Net::DNS::RR::OPT::DAU);
package Net::DNS::RR::OPT::N3U; # RFC6975
-use base qw(Net::DNS::RR::OPT::DAU);
+use parent -norequire, qw(Net::DNS::RR::OPT::DAU);
package Net::DNS::RR::OPT::CLIENT_SUBNET; # RFC7871