]> git.sur5r.net Git - openldap/blobdiff - libraries/liblmdb/mdb.c
ITS#7992 Fix memleak in prev change
[openldap] / libraries / liblmdb / mdb.c
index 09f5132599de72945d06fceaacd7dd4f9e9d5977..ea9e4729025f4934af2a0e473d268f8b9973385d 100644 (file)
@@ -5,7 +5,7 @@
  *     BerkeleyDB API, but much simplified.
  */
 /*
- * Copyright 2011-2015 Howard Chu, Symas Corp.
+ * Copyright 2011-2016 Howard Chu, Symas Corp.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE 1
 #endif
-#ifdef MDB_VL32
+#if defined(MDB_VL32) || defined(__WIN64__)
 #define _FILE_OFFSET_BITS      64
 #endif
 #ifdef _WIN32
@@ -1075,7 +1075,7 @@ typedef struct MDB_db {
        pgno_t          md_branch_pages;        /**< number of internal pages */
        pgno_t          md_leaf_pages;          /**< number of leaf pages */
        pgno_t          md_overflow_pages;      /**< number of overflow pages */
-       pgno_t          md_entries;             /**< number of data items */
+       mdb_size_t      md_entries;             /**< number of data items */
        pgno_t          md_root;                /**< the root page of this tree */
 } MDB_db;
 
@@ -2428,8 +2428,8 @@ mdb_page_alloc(MDB_cursor *mc, int num, MDB_page **mp)
                        rc = MDB_MAP_FULL;
                        goto fail;
        }
-#ifdef _WIN32
-       if (env->me_flags & MDB_WRITEMAP) {
+#if defined(_WIN32) && !defined(MDB_VL32)
+       if (!(env->me_flags & MDB_RDONLY)) {
                void *p;
                p = (MDB_page *)(env->me_map + env->me_psize * pgno);
                p = VirtualAlloc(p, env->me_psize * num, MEM_COMMIT,
@@ -4272,7 +4272,7 @@ mdb_env_set_mapsize(MDB_env *env, mdb_size_t size)
                        size = meta->mm_mapsize;
                {
                        /* Silently round up to minimum if the size is too small */
-                       size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
+                       mdb_size_t minsize = (meta->mm_last_pg + 1) * env->me_psize;
                        if (size < minsize)
                                size = minsize;
                }
@@ -5255,14 +5255,16 @@ mdb_env_close0(MDB_env *env, int excl)
        free(env->me_dbflags);
        free(env->me_path);
        free(env->me_dirty_list);
-       free(env->me_txn0);
 #ifdef MDB_VL32
+       if (env->me_txn0 && env->me_txn0->mt_rpages)
+               free(env->me_txn0->mt_rpages);
        { unsigned int x;
                for (x=1; x<=env->me_rpages[0].mid; x++)
                munmap(env->me_rpages[x].mptr, env->me_rpages[x].mcnt * env->me_psize);
        }
        free(env->me_rpages);
 #endif
+       free(env->me_txn0);
        mdb_midl_free(env->me_free_pgs);
 
        if (env->me_flags & MDB_ENV_TXKEY) {
@@ -5764,7 +5766,7 @@ notlocal:
                pthread_mutex_lock(&env->me_rpmutex);
 retry:
                y = 0;
-               for (i=1; i<tl[0].mid; i++) {
+               for (i=1; i<=tl[0].mid; i++) {
                        if (!tl[i].mref) {
                                if (!y) y = i;
                                /* tmp overflow pages don't go to env */
@@ -5828,7 +5830,7 @@ retry:
                                if (rc)
                                        goto fail;
                                if (!el[x].mref) {
-                                       munmap(el[x].mptr, el[x].mcnt);
+                                       munmap(el[x].mptr, env->me_psize * el[x].mcnt);
                                        el[x].mptr = id3.mptr;
                                        el[x].mcnt = id3.mcnt;
                                } else {
@@ -5844,7 +5846,7 @@ retry:
                if (el[0].mid >= MDB_ERPAGE_MAX - env->me_rpcheck) {
                        /* purge unref'd pages */
                        unsigned i, y = 0;
-                       for (i=1; i<el[0].mid; i++) {
+                       for (i=1; i<=el[0].mid; i++) {
                                if (!el[i].mref) {
                                        if (!y) y = i;
                                        munmap(el[i].mptr, env->me_psize * el[i].mcnt);
@@ -5880,36 +5882,15 @@ fail:
                        pthread_mutex_unlock(&env->me_rpmutex);
                        return rc;
                }
-               /* If this page is far enough from the end of the env, scan for
-                * any overflow pages that would spill onto another block.
-                * Note we must compare against mt_last_pgno, the last written
-                * page in the environment. Not mt_next_pgno, which increases
-                * for every newly allocated (but not yet written) page. If
-                * we scanned beyond the last written page we'd get a bus error.
-                */
-               if (pgno + MDB_RPAGE_CHUNK <= txn->mt_last_pgno) {
-                       int i;
-                       char *cp = (char *)id3.mptr + rem * env->me_psize;
-                       for (i=rem; i<MDB_RPAGE_CHUNK;) {
-                               p = (MDB_page *)cp;
-                               if (IS_OVERFLOW(p)) {
-                                       int nop = p->mp_pages;
-                                       if (nop + i > MDB_RPAGE_CHUNK) {
-                                               munmap(id3.mptr, len);
-                                               id3.mcnt = nop + i;
-                                               len = id3.mcnt * env->me_psize;
-                                               MAP(rc, env, id3.mptr, len, off);
-                                               if (rc)
-                                                       goto fail;
-                                               break;
-                                       }
-                                       i += nop;
-                                       cp += nop * env->me_psize;
-                               } else {
-                                       i++;
-                                       cp += env->me_psize;
-                               }
-                       }
+               /* check for overflow size */
+               p = (MDB_page *)((char *)id3.mptr + rem * env->me_psize);
+               if (IS_OVERFLOW(p) && p->mp_pages + rem > id3.mcnt) {
+                       id3.mcnt = p->mp_pages + rem;
+                       munmap(id3.mptr, len);
+                       len = id3.mcnt * env->me_psize;
+                       MAP(rc, env, id3.mptr, len, off);
+                       if (rc)
+                               goto fail;
                }
                mdb_mid3l_insert(el, &id3);
                pthread_mutex_unlock(&env->me_rpmutex);
@@ -6456,8 +6437,10 @@ mdb_cursor_next(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
 
        DPRINTF(("cursor_next: top page is %"Y"u in cursor %p",
                mdb_dbg_pgno(mp), (void *) mc));
-       if (mc->mc_flags & C_DEL)
+       if (mc->mc_flags & C_DEL) {
+               mc->mc_flags ^= C_DEL;
                goto skip;
+       }
 
        if (mc->mc_ki[mc->mc_top] + 1u >= NUMKEYS(mp)) {
                DPUTS("=====> move to next sibling page");
@@ -6543,6 +6526,8 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op)
        DPRINTF(("cursor_prev: top page is %"Y"u in cursor %p",
                mdb_dbg_pgno(mp), (void *) mc));
 
+       mc->mc_flags &= ~(C_EOF|C_DEL);
+
        if (mc->mc_ki[mc->mc_top] == 0)  {
                DPUTS("=====> move to prev sibling page");
                if ((rc = mdb_cursor_sibling(mc, 0)) != MDB_SUCCESS) {
@@ -6997,6 +6982,28 @@ fetchm:
                        }
                }
                break;
+       case MDB_PREV_MULTIPLE:
+               if (data == NULL) {
+                       rc = EINVAL;
+                       break;
+               }
+               if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+                       rc = MDB_INCOMPATIBLE;
+                       break;
+               }
+               if (!(mc->mc_flags & C_INITIALIZED))
+                       rc = mdb_cursor_first(mc, key, data);
+               else {
+                       MDB_cursor *mx = &mc->mc_xcursor->mx_cursor;
+                       if (mx->mc_flags & C_INITIALIZED) {
+                               rc = mdb_cursor_sibling(mx, 0);
+                               if (rc == MDB_SUCCESS)
+                                       goto fetchm;
+                       } else {
+                               rc = MDB_NOTFOUND;
+                       }
+               }
+               break;
        case MDB_NEXT:
        case MDB_NEXT_DUP:
        case MDB_NEXT_NODUP:
@@ -7538,7 +7545,7 @@ new_sub:
                 */
                if (do_sub) {
                        int xflags, new_dupdata;
-                       size_t ecount;
+                       mdb_size_t ecount;
 put_sub:
                        xdata.mv_size = 0;
                        xdata.mv_data = "";
@@ -8253,7 +8260,7 @@ mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc)
 
 /* Return the count of duplicate data items for the current key */
 int
-mdb_cursor_count(MDB_cursor *mc, size_t *countp)
+mdb_cursor_count(MDB_cursor *mc, mdb_size_t *countp)
 {
        MDB_node        *leaf;
 
@@ -10113,7 +10120,7 @@ mdb_env_copy2(MDB_env *env, const char *path, unsigned int flags)
 #ifdef _WIN32
        rc = utf8_to_utf16(lpath, -1, &wpath, NULL);
        if (rc)
-               return rc;
+               goto leave;
        newfd = CreateFileW(wpath, GENERIC_WRITE, 0, NULL, CREATE_NEW,
                                FILE_FLAG_NO_BUFFERING|FILE_FLAG_WRITE_THROUGH, NULL);
        free(wpath);