lukaswhl@gmail.com wrote:
Full_Name: Lukas W Version: mdb.master c367c1f69685a4d307acb8cea6945c1d67e1cc7e OS: Linux URL: ftp://ftp.openldap.org/incoming/ Submission from: (NULL) (114.23.231.86)
Replacing values in sub-databases (with MDB_DUPSORT) can lead to the new data's length being ignored. This specific example reproduces the problem (creating the entries "1"->"ABC", and "1"->2a2abc"):
[…] mdb_dbi_open(txn, NULL, MDB_DUPSORT, &dbi); key.mv_size = 2; key.mv_data = "1"; data.mv_size = 4; data.mv_data = "ABC"; mdb_put(txn, dbi, &key, &data, 0); data.mv_data = "abc"; mdb_put(txn, dbi, &key, &data, 0);
If one later tries to change a value of one of the existing entries, the new value is being copied, but the size is not changed. This could lead to database corruption if the new value is longer than the old one as the length of the new value is used in memcpy.
key.mv_ze % = 2; key.mv_data = "1"; data.mv_size = 4; data.mv_data = "abc"; mdb_cursor_get(cursor, &key, &data, MDB_GET_BOTH);
data.mv_size = 2; data.mv_data = "Q"; mdb_cursor_put(cursor, &key, &data, MDB_CURRENT);
This is a misuse of MDB_CURRENT: as documented, the new value is supposed to be the same size as the existing value.
mdb_cursor_get(cursor, &key, &data, MDB_GET_CURRENT); printf("%s (%d)\n", data.mv_size);
This will output "Q (4)", while it should output "Q (2)". Note that the data in the DB probably is "Q\0c", printf just stops at the null character. The value is written in mdb.c:7516. Context:
[…] /* same size, just replace it. Note that we could * also reuse this node if the new data is smaller, * but instead we opt to shrink the node in that case. */ if (F_ISSET(flags, MDB_RESERVE)) data->mv_data = olddata.mv_data; else if (!(mc->mc_flags & C_SUB)) memcpy(olddata.mv_data, data->mv_data, data->mv_size); else { 7516: memcpy(NODEKEY(leaf), key->mv_data, key->mv_size); goto fix_parent; } […]