https://bugs.openldap.org/show_bug.cgi?id=9430
Issue ID: 9430 Summary: mdb_put() with MDB_RESERVE | MDB_NOOVERWRITE sets 'data' to invalid memory Product: LMDB Version: unspecified Hardware: x86_64 OS: Linux Status: UNCONFIRMED Severity: normal Priority: --- Component: liblmdb Assignee: bugs@openldap.org Reporter: kenta@lithdew.net Target Milestone: ---
Running on NixOS (x86_64-linux).
The following sequence of methods was called with an MDB_env and MDB_txn created with default flags, with the MDB_txn open on MAIN_DBI.
The following code is pseudocode - should the code not be clear enough, happy to provide the original test case which was written in Zig (https://ziglang.org).
// Put KV pair ('hello', 'test').
var k: MDB_val = .{ .mv_size = "hello".len, .mv_data = &"hello" }; var v: MDB_val = .{ .mv_size = "test".len, .mv_data = &"test" }; mdb_put(txn, MAIN_DBI, &k, &v, 0);
// Attempt to put KV pair ('hello', 'world!') with MDB_RESERVE | MDB_NOOVERWRITE, and assert that it fails.
var k2: MDB_val = .{ .mv_size = "hello".len, .mv_data = &"hello" }; var v2: MDB_val = .{ .mv_size = "world!".len, .mv_data = null }; assert(mdb_put(txn, MAIN_DBI, &k2, &v2, MDB_RESERVE | MDB_NOOVERWRITE) == MDB_KEYEXIST);
// Assertion fails. assert(v2 == v);
After these steps, it is expected that v2's 'mv_data' points to 'test' with a 'mv_size' of 4 (the previously, successfully-written KV pair).
What actually happened was that v2's 'mv_size' was correctly set to 4, though 'mv_data' points to garbage memory.
https://bugs.openldap.org/show_bug.cgi?id=9430
--- Comment #1 from Howard Chu hyc@openldap.org --- (In reply to kenta from comment #0)
Running on NixOS (x86_64-linux).
The following sequence of methods was called with an MDB_env and MDB_txn created with default flags, with the MDB_txn open on MAIN_DBI.
The following code is pseudocode - should the code not be clear enough, happy to provide the original test case which was written in Zig (https://ziglang.org).
// Put KV pair ('hello', 'test'). var k: MDB_val = .{ .mv_size = "hello".len, .mv_data = &"hello" }; var v: MDB_val = .{ .mv_size = "test".len, .mv_data = &"test" }; mdb_put(txn, MAIN_DBI, &k, &v, 0); // Attempt to put KV pair ('hello', 'world!') with MDB_RESERVE |
MDB_NOOVERWRITE, and assert that it fails.
var k2: MDB_val = .{ .mv_size = "hello".len, .mv_data = &"hello" }; var v2: MDB_val = .{ .mv_size = "world!".len, .mv_data = null }; assert(mdb_put(txn, MAIN_DBI, &k2, &v2, MDB_RESERVE | MDB_NOOVERWRITE)
== MDB_KEYEXIST);
// Assertion fails. assert(v2 == v);
After these steps, it is expected that v2's 'mv_data' points to 'test' with a 'mv_size' of 4 (the previously, successfully-written KV pair).
What actually happened was that v2's 'mv_size' was correctly set to 4, though 'mv_data' points to garbage memory.
Unable to reproduce, code works and returns the expected value for me.
https://bugs.openldap.org/show_bug.cgi?id=9430
kenta@lithdew.net changed:
What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED
--- Comment #2 from kenta@lithdew.net --- Found out the issue was due to a miscompilation from Zig's end - apologies on my end. I wrote the pseudocode test case up in C just to be extra sure.
#include <stdio.h> #include <assert.h> #include "lmdb.h"
int main(int argc, char * argv[]) { MDB_env *env; MDB_dbi dbi; MDB_val key, data; MDB_txn *txn; MDB_cursor *cursor; char sval[32];
assert(mdb_env_create(&env) == MDB_SUCCESS); assert(mdb_env_set_maxdbs(env, 2) == MDB_SUCCESS); assert(mdb_env_open(env, "./testdb", MDB_NOSUBDIR | MDB_WRITEMAP, 0664) == MDB_SUCCESS); assert(mdb_txn_begin(env, NULL, 0, &txn) == MDB_SUCCESS); assert(mdb_open(txn, NULL, 0, &dbi) == MDB_SUCCESS);
key.mv_data = "hello"; key.mv_size = sizeof(key.mv_data) - 1; data.mv_data = "test"; data.mv_size = sizeof(data.mv_data) - 1; assert(mdb_put(txn, dbi, &key, &data, 0) == MDB_SUCCESS);
data.mv_data = "world!"; data.mv_size = sizeof(data.mv_data) - 1; printf("(key: %s) -> (data: %s)\n", key.mv_data, data.mv_data); assert(mdb_put(txn, dbi, &key, &data, MDB_RESERVE | MDB_NOOVERWRITE) == MDB_KEYEXIST);
printf("(key: %s) -> (data: %s)\n", key.mv_data, data.mv_data);
mdb_close(env, dbi); mdb_env_close(env); return 0; }
https://bugs.openldap.org/show_bug.cgi?id=9430
Quanah Gibson-Mount quanah@openldap.org changed:
What |Removed |Added ---------------------------------------------------------------------------- Status|RESOLVED |VERIFIED