]> git.sur5r.net Git - openldap/commitdiff
Fix alloc/free issues.
authorHallvard Furuseth <hallvard@openldap.org>
Wed, 26 Jun 2013 16:02:52 +0000 (18:02 +0200)
committerHallvard Furuseth <hallvard@openldap.org>
Wed, 26 Jun 2013 16:02:52 +0000 (18:02 +0200)
Page leak, mdb_page_alloc(). On error, don't shorten me_pghead.
Memleak, mdb_ovpage_free(). Free page or keep it in dirty_list.
Bad MIDL, mdb_midl_need(). Fix midl[-1] (allocated size).

libraries/liblmdb/mdb.c
libraries/liblmdb/midl.c

index 53568dc92b22fb3d70b0993e1909759b2da07846..d9cac574cf39fafc922216c42682960858f02763 100644 (file)
@@ -1367,12 +1367,13 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
        MDB_txn *txn = mc->mc_txn;
        MDB_env *env = txn->mt_env;
        pgno_t pgno, *mop = env->me_pghead;
-       unsigned mop_len = mop ? mop[0] : 0;
+       unsigned i, j, k, mop_len = mop ? mop[0] : 0;
        MDB_page *np;
        MDB_ID2 mid;
        txnid_t oldest = 0, last;
        MDB_cursor_op op;
        MDB_cursor m2;
+       int (*insert)(MDB_ID2L, MDB_ID2 *);
 
        *mp = NULL;
 
@@ -1381,7 +1382,6 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                return MDB_TXN_FULL;
 
        for (op = MDB_FIRST;; op = MDB_NEXT) {
-               unsigned int i, j, k;
                MDB_val key, data;
                MDB_node *leaf;
                pgno_t *idl, old_id, new_id;
@@ -1393,13 +1393,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                        i = mop_len;
                        do {
                                pgno = mop[i];
-                               if (mop[i-n2] == pgno+n2) {
-                                       mop[0] = mop_len -= num;
-                                       /* Move any stragglers down */
-                                       for (j = i-n2; j <= mop_len; )
-                                               mop[j++] = mop[++i];
+                               if (mop[i-n2] == pgno+n2)
                                        goto search_done;
-                               }
                        } while (--i >= (unsigned)num);
                        if (Max_retries < INT_MAX && --retry < 0)
                                break;
@@ -1471,34 +1466,33 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
        }
 
        /* Use new pages from the map when nothing suitable in the freeDB */
-       pgno = P_INVALID;
-       if (txn->mt_next_pgno + num >= env->me_maxpg) {
+       i = 0;
+       pgno = txn->mt_next_pgno;
+       if (pgno + num >= env->me_maxpg) {
                        DPUTS("DB size maxed out");
                        return MDB_MAP_FULL;
        }
 
 search_done:
        if (env->me_flags & MDB_WRITEMAP) {
-               if (pgno == P_INVALID) {
-                       pgno = txn->mt_next_pgno;
-                       txn->mt_next_pgno += num;
-               }
                np = (MDB_page *)(env->me_map + env->me_psize * pgno);
+               insert = mdb_mid2l_append;
        } else {
                if (!(np = mdb_page_malloc(txn, num)))
                        return ENOMEM;
-               if (pgno == P_INVALID) {
-                       pgno = txn->mt_next_pgno;
-                       txn->mt_next_pgno += num;
-               }
+               insert = mdb_mid2l_insert;
        }
-       mid.mid = np->mp_pgno = pgno;
-       mid.mptr = np;
-       if (env->me_flags & MDB_WRITEMAP) {
-               mdb_mid2l_append(txn->mt_u.dirty_list, &mid);
+       if (i) {
+               mop[0] = mop_len -= num;
+               /* Move any stragglers down */
+               for (j = i-num; j < mop_len; )
+                       mop[++j] = mop[++i];
        } else {
-               mdb_mid2l_insert(txn->mt_u.dirty_list, &mid);
+               txn->mt_next_pgno = pgno + num;
        }
+       mid.mid = np->mp_pgno = pgno;
+       mid.mptr = np;
+       insert(txn->mt_u.dirty_list, &mid);
        txn->mt_dirty_room--;
        *mp = np;
 
@@ -4231,16 +4225,21 @@ mdb_ovpage_free(MDB_cursor *mc, MDB_page *mp)
                /* Remove from dirty list */
                dl = txn->mt_u.dirty_list;
                x = dl[0].mid--;
-               for (ix = dl[x]; ix.mid != pg; ix = iy) {
+               for (ix = dl[x]; ix.mptr != mp; ix = iy) {
                        if (x > 1) {
                                x--;
                                iy = dl[x];
                                dl[x] = ix;
                        } else {
                                assert(x > 1);
+                               j = ++(dl[0].mid);
+                               dl[j] = ix;             /* Unsorted. OK when MDB_TXN_ERROR. */
+                               txn->mt_flags |= MDB_TXN_ERROR;
                                return MDB_CORRUPTED;
                        }
                }
+               if (!(env->me_flags & MDB_WRITEMAP))
+                       mdb_dpage_free(env, mp);
                /* Insert in me_pghead */
                mop = env->me_pghead;
                j = mop[0] + ovpages;
index 0fcedbe661d0edc6db5d758d247bffdebd9d3a7a..e7bd680cb015f5dad2cc9d0923c7d09f0d832e9e 100644 (file)
@@ -150,7 +150,7 @@ int mdb_midl_need( MDB_IDL *idp, unsigned num )
                num = (num + num/4 + (256 + 2)) & -256;
                if (!(ids = realloc(ids-1, num * sizeof(MDB_ID))))
                        return ENOMEM;
-               *ids++ += num -= 2;
+               *ids++ = num -= 2;
                *idp = ids;
        }
        return 0;