h.b.furuseth@usit.uio.no wrote:
Full_Name: Hallvard B Furuseth Version: LMDB_0.9.13 OS: Linux x86_64 URL: Submission from: (NULL) (81.191.45.35) Submitted by: hallvard
Allocate an ovpage from mt_next_pgno, mdb_ovpage_free() it and commit: The datafile may end before MDB_meta.mm_last_pg since the ovpage was never written. mdb_env_copyfd() & co break when they read the file to mm_last_pg.
fixed in mdb.master
Same with loose pages if mdb_page_flush() skipped them, which it could: ecde3a4008f5080d8264926f49680db27804787f in my branch mdb/loose3.
Bug demo:
rm data.mdb; ./a.out && ./mdb_copy . > copy.mdb ./mdb_copy: copying failed, error 14 (Bad address)
(Piping it to /dev/null succeeds on Linux, apparently it doesn't read anything.)
#include "lmdb.h" #include <stdio.h> #include <stdlib.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()))
int main(void) { int rc; unsigned sz; MDB_env *env; MDB_txn *txn; MDB_dbi dbi; static char buf[20000]; E(mdb_env_create(&env)); E(mdb_env_open(env, ".", 0, 0664)); for (sz = 0; sz<=sizeof(buf); sz = (sz==2 ? sizeof(buf) : sz+1)) { E(mdb_txn_begin(env, NULL, 0, &txn)); E(mdb_dbi_open(txn, NULL, 0, &dbi)); E(mdb_put(txn, dbi, &(MDB_val){4,&sz}, &(MDB_val){sz,buf}, 0)); if (sz) E(mdb_del(txn, dbi, &(MDB_val){4,&sz}, NULL)); E(mdb_txn_commit(txn)); } mdb_env_close(env); return 0; }