[Date Prev][Date Next]
[Chronological]
[Thread]
[Top]
(ITS#7886) mdb_ovpage_free() can break mdb_copy
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.
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;
}