Dear list
the current version (1.23 from SVN) of the memcached perl client crash when it 
once fail to connect an host and the
success to connect to another host.

On my workstation (Linux ubuntu 6.10), when the problem occurs i get :

[EMAIL PROTECTED]:~/work/memcached-ref/api/perl$ perl mctest.pl
using parser: Cache::Memcached::GetParser
*** glibc detected *** perl: munmap_chunk(): invalid pointer: 0x081fd690 ***
======= Backtrace: =========
/lib/tls/i686/cmov/libc.so.6(__libc_free+0x18a)[0xb7e02b4a]
perl(Perl_sv_setsv_flags+0x5cb)[0x80d370f]
perl(Perl_pp_sassign+0x56)[0x80c37e4]
perl(Perl_runops_standard+0x13)[0x80bb273]
perl(perl_run+0x2e1)[0x80639b4]
perl(main+0x112)[0x8060012]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xdc)[0xb7db18cc]
perl[0x805fe81]
======= Memory map: ========


The GetParserXS module is NOT installed
After some sessions of debugging it appears that it is Perl which fools itself 
when executing :
  $sock = $buck2sock[$bucket] ||= $self->sock_to_host($self->{buckets}[ $bucket 
]

When sock_to_host had returned undef (because it had been unable to connect to 
the desired server), the next execution
of this line will crash when trying to set the return value of sock_to_host 
into $buck2sock[$bucket]

The test case is in the mctest.pl (I simulate the timeout on connect by NOT 
having a memcache server listening on 11212).

I fix the bug by simplifying the code and splitting into smaller pieces (see 
the patch attached to this mail).

Cheers
Matthieu


#!/usr/local/bin/perl -w

use strict;
use Cache::Memcached;

my $a = new Cache::Memcached {
		servers => [
				"127.0.0.1:11211",
				"127.0.0.1:11212",
			],
		};
$a->get_multi(("ad_formats"));
$a->get_multi("ad_formats2");
print "Done!\n";

--- lib/Cache/Memcached.pm      2007-06-27 09:49:29.544348857 +0200
+++ Cache/Memcached.pm  2007-06-27 10:43:34.565272061 +0200
@@ -567,8 +567,11 @@
             my $tries;
             while (1) {
                 my $bucket = $hv % $bcount;
-                $sock = $buck2sock[$bucket] ||= 
$self->sock_to_host($self->{buckets}[ $bucket ])
-                    and last;
+                $sock = $buck2sock[$bucket] || 
$self->sock_to_host($self->{buckets}[ $bucket ]);
+               if ($sock) {
+                       $buck2sock[$bucket] = $sock;
+                       last;
+               }
                 next KEY if $tries++ >= 20;
                 $hv += _hashfunc($tries . $real_key);
             }

Reply via email to