[Date Prev][Date Next] [Chronological] [Thread] [Top]

(ITS#7828) LMDB crash in mdb_cursor_put(MDB_CURRENT)



Full_Name: Dmitri Shubin
Version: LMDB 0.9.11 (2727e97)
OS: Linux (CentOS 6)
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (80.239.140.98)


Hi!

I got a crash inside LMDB in mdb_cursor_put() functions when I trying to modify
the record under cursor.

Simple test:

$ cat test-mdb_current.c 
#include <stdio.h>
#include <stdlib.h>

#include "lmdb.h"

#define E(expr) CHECK((rc = (expr)) == MDB_SUCCESS, #expr)
#define CHECK(test, msg) ((test) ? (void)0 : ((void)fprintf(stderr, \
    "%s:%d: %s: %s\n", __FILE__, __LINE__, msg, mdb_strerror(rc)), abort()))

#define DBDIR "./testdb"

int main()
{
    int rc;
    MDB_env *env;
    MDB_dbi dbi;
    MDB_txn *txn;
    MDB_val key, data;
    MDB_cursor *cursor;

    int key_v = 17;
    char data_v[] = "0123456789";

    E(system("rm -rf " DBDIR " && mkdir " DBDIR));

    E(mdb_env_create(&env));
    E(mdb_env_open(env, DBDIR, 0, 0664));

    E(mdb_txn_begin(env, NULL, 0, &txn));
    E(mdb_dbi_open(txn, NULL, 0, &dbi));

    /* put some data */
    key.mv_data = &key_v;
    key.mv_size = sizeof(key_v);
    data.mv_data = data_v;
    data.mv_size = sizeof(data_v);

    E(mdb_put(txn, dbi, &key, &data, 0));

    E(mdb_txn_commit(txn));

    /* replace using cursor */
    E(mdb_txn_begin(env, NULL, 0, &txn));

    E(mdb_cursor_open(txn, dbi, &cursor));

    E(mdb_cursor_get(cursor, &key, &data, MDB_SET));

    data.mv_data = data_v;
    data.mv_size = sizeof(data_v) - 1;
    E(mdb_cursor_put(cursor, &key, &data, MDB_CURRENT));

    mdb_cursor_close(cursor);

    E(mdb_txn_commit(txn));

    mdb_dbi_close(env, dbi);
    mdb_env_close(env);

    return 0;
}
$ gcc -g test-mdb_current.c  -llmdb -L. -Wl,-rpath,.
$ ./a.out 
Segmentation fault (core dumped)
$ gdb a.out
...
Program terminated with signal 11, Segmentation fault.
#0  0x00007fefaba9895c in mdb_leaf_size (env=0xbd8010, key=0x0,
data=0x7fff59e6a830) at mdb.c:6430
6430            sz = LEAFSIZE(key, data);
(gdb) bt
#0  0x00007fefaba9895c in mdb_leaf_size (env=0xbd8010, key=0x0,
data=0x7fff59e6a830) at mdb.c:6430
#1  0x00007fefaba97c53 in mdb_cursor_put (mc=0xbda2f0, key=0x0,
data=0x7fff59e6a830, flags=64) at mdb.c:6178
#2  0x0000000000400ee0 in main () at test-mdb_current.c:51
(gdb) l
6425    static size_t
6426    mdb_leaf_size(MDB_env *env, MDB_val *key, MDB_val *data)
6427    {
6428            size_t           sz;
6429
6430            sz = LEAFSIZE(key, data);
6431            if (sz > env->me_nodemax) {
6432                    /* put on overflow page */
6433                    sz -= data->mv_size - sizeof(pgno_t);
6434            }
(gdb) p key
$1 = (MDB_val *) 0x0

If I remove MDB_CURRENT flag from mdb_cursor_put() call it works fine.

Thanks!