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

(ITS#7972) zgrim



Full_Name: zgrim
Version: 2.4.40
OS: Linux
URL: ftp://ftp.openldap.org/incoming/
Submission from: (NULL) (79.115.186.237)


 Hello, thank you for lmdb.
 I'm using lmdb via a Go wrapper and under some not-yet-clear circumstances,
under high concurrency stress testing,
I sometimes get "double free or corruption" SIGABRT related to
mdb_dbis_update().
 The setup is using the NOTLS and RDONLY flags on a 64bit 3.17.0 Arch Linux
system.
 If I protect the free() inside mdb_dbis_update() (in mdb.c) with a mutex (code
inline below), the symptom disappears.
 I'm sorry I can't provide a simple test case, but in my code, without the
mutex, launching some tens of test clients simultaneously trigger the
corruption fairly quick, i.e. a few minutes or even seconds.

 I tried older releases of lmdb as well as the latest git tree,
9a8eb95674c7b500cfe5f44d03493ff76c9fc0c1 of mdb.master, the bahaviour is the
same.

 I also tried several approaches in the higher level code, like either txn reset
and renew and a pool of txns or simplified the code to bare bones
to just abort after each transaction and remake new txns, it does not matter,
the corruption happens the same.

 If the problem should lie in the higher level code, I'd welcome your insights
on possible culprits, I'm very new to lmdb.
Thanks.

against latest git mentioned above i applied something like,

@@ -2769,19 +2769,24 @@
        MDB_dbi n = txn->mt_numdbs;
        MDB_env *env = txn->mt_env;
        unsigned char *tdbflags = txn->mt_dbflags;
+       int rc = 0, rx = 0;

        for (i = n; --i >= 2;) {
                if (tdbflags[i] & DB_NEW) {
                        if (keep) {
                                env->me_dbflags[i] = txn->mt_dbs[i].md_flags |
MDB_VALID;
                        } else {
-                               char *ptr = env->me_dbxs[i].md_name.mv_data;
-                               if (ptr) {
+                               if (env->me_dbxs[i].md_name.mv_data != NULL) {
+                                       mdb_mutex_t *wmutex = MDB_MUTEX(env,
w);
+                                       rc = LOCK_MUTEX(rx, env, wmutex);
+
+                                       free(env->me_dbxs[i].md_name.mv_data);
                                        env->me_dbxs[i].md_name.mv_data = NULL;
                                        env->me_dbxs[i].md_name.mv_size = 0;
                                        env->me_dbflags[i] = 0;
                                        env->me_dbiseqs[i]++;
-                                       free(ptr);
+
+                                       if (!rc) UNLOCK_MUTEX(wmutex);
                                }
                        }
                }