libmemcached crash after memcached_servers_reset() and subsequent memcached_server_add()

Bug #1626565 reported by Denis
8
This bug affects 1 person
Affects Status Importance Assigned to Milestone
libmemcached
New
Undecided
Unassigned

Bug Description

libmemcached 1.0.18

When used with MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED at memcached_servers_reset ketama.continuum is freed, NULL-ed, but ketama.continuum_count is not zeroed. It leads to segfault when memcached_server_add() is accessing ketama.continuum[0].

The following code is a proof:

#include <libmemcached/memcached.h>
#include <stdio.h>

int main() {
        const char *config_string= "--SERVER=localhost";
        const char *key= "foo";
        const char *value= "bar";
        memcached_return_t err;
        size_t retlen;
        char *retvalue;
        memcached_st *memc= memcached(config_string, strlen(config_string));
        err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);
        if (err != MEMCACHED_SUCCESS) {
                printf("behavior set failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        err= memcached_server_add(memc, "localhost", 11211);
        if (err != MEMCACHED_SUCCESS) {
                printf("server add failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);
        if (err != MEMCACHED_SUCCESS) {
                printf("set failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);
        if (retvalue) {
                printf("%s\n", retvalue);
        } else {
                printf("get failed, %s\n", memcached_strerror(memc, err));
        }

        memcached_servers_reset(memc);

        err= memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_KETAMA_WEIGHTED, true);
        if (err != MEMCACHED_SUCCESS) {
                printf("behavior set 2 failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        err= memcached_server_add(memc, "localhost", 11211);
        if (err != MEMCACHED_SUCCESS) {
                printf("server add 2 failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        err= memcached_set(memc, key, strlen(key), value, strlen(value), 0, 0);
        if (err != MEMCACHED_SUCCESS) {
                printf("set 2 failed, %s\n", memcached_strerror(memc, err));
                exit(1);
        }
        retvalue= memcached_get(memc, key, strlen(key), &retlen, 0, &err);
        if (retvalue) {
                printf("%s\n", retvalue);
        } else {
                printf("get 2 failed, %s\n", memcached_strerror(memc, err));
        }

        memcached_free(memc);

}

Actual behavior:

$ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb
$ ./memcached_bug
bar
Segmentation fault (core dumped)

Expected behavior:

$ gcc memcached_bug.c -o memcached_bug -lmemcached -ggdb
$ ./memcached_bug
bar
bar

gdb output:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316
316 ptr->ketama.continuum[continuum_index].index= host_index;
(gdb) bt
#0 0x00007ffff7bbef3d in update_continuum (ptr=0x614c20) at libmemcached/hosts.cc:316
#1 0x00007ffff7bbf8f6 in memcached_server_add_with_weight (shell=0x614c20, hostname=<optimized out>, port=<optimized out>, weight=0) at libmemcached/hosts.cc:585
#2 0x0000000000400c56 in main ()
(gdb) list
311 if (memcached_is_weighted_ketama(ptr))
312 {
313 for (uint32_t x = 0; x < pointer_per_hash; x++)
314 {
315 uint32_t value= ketama_server_hash(sort_host, (size_t)sort_host_length, x);
316 ptr->ketama.continuum[continuum_index].index= host_index;
317 ptr->ketama.continuum[continuum_index++].value= value;
318 }
319 }
320 else
(gdb) print ptr->ketama.continuum
$1 = (memcached_continuum_item_st *) 0x0
(gdb) print ptr->ketama.continuum_count
$2 = 11
(gdb) quit

Attached is a patch to fix that.

Denis (denis.y)
description: updated
Denis (denis.y)
description: updated
Revision history for this message
Denis (denis.y) wrote :

re-uploaded a better patch

Revision history for this message
Denis (denis.y) wrote :
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.