Brothers, I'm going mad with this and probably just need a whack on the head to make me see what's right in front of my eyes. I'm the author of the Net::CIDR::Lookup module and have been getting a lot of cpantesters failures. While some of them are due to a broken/incomplete Socket implementation on Windows and thus Other People's Problem, there are some related to the _add method that always look like this:
# Failed test 'add died (Modification of non-creatable array value attempted, subscript -1 at /home/cpan/pit/bare/conf/perl-5.16.0/.cpanplus/5.16.0/build/Net-CIDR-Lookup-0.51/blib/lib/Net/CIDR/Lookup.pm line 342.
# ...propagated at t/lib/Net/CIDR/Lookup/Test.pm line 41.)'
# at t/Net-CIDR-Lookup.t line 6.
# (in Net::CIDR::Lookup::Test->add)
The code that fails here by resulting in a negative subscript is basically this (it's a bit more convoluted but as $bit isn't modified in between the initial assignment and the array creation, this is what it boils down to):
$bit = ($addr & 0x80000000) >> 31;
+
$addr <<= 1;
+
$node->[$bit] ||= bless([], __PACKAGE__);
The idea is to make every node an array of one or two elements by using the current bit from the IP address as an index. Somehow this bit seems to come out -1 sometimes, on a wide range of systems and Perl versions. I've never been able to reproduce it though, nor can I think of a number that masked and shifted that way would result in -1. Even if the upper 32 bit on a 64 bit system should contain garbage for some reason, the mask should eliminate it, right?
Lately I've augmented the test so it first checks whether _add() dies, and if so, monkey-patches it with a version that tries to trace where the error happens. As soon as I do that---add a single print statement to the start and one after the bit shift, plus replaced some instances of __PACKAGE__ with 'Net::CIDR::Lookup' because of the different definition context---the heisenbug is gone. WTF?!