mdbx: refine/fix handling MDBX_MULTIPLE in the mdbx_cursor_put().

Change-Id: I06ac9d73cec01afb492b5c663acf310d19e4900b
This commit is contained in:
Leonid Yuriev 2020-08-24 16:19:38 +03:00
parent 426d207fc4
commit 89dba59ce2

View File

@ -12059,10 +12059,7 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
MDBX_page *sub_root = NULL; MDBX_page *sub_root = NULL;
MDBX_val xdata, *rdata, dkey, olddata; MDBX_val xdata, *rdata, dkey, olddata;
MDBX_db nested_dupdb; MDBX_db nested_dupdb;
unsigned mcount = 0, dcount = 0, nospill;
size_t nsize;
int rc2; int rc2;
unsigned nflags;
DKBUF; DKBUF;
if (unlikely(mc == NULL || key == NULL || data == NULL)) if (unlikely(mc == NULL || key == NULL || data == NULL))
@ -12078,13 +12075,22 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
env = mc->mc_txn->mt_env; env = mc->mc_txn->mt_env;
/* Check this first so counter will always be zero on any early failures. */ /* Check this first so counter will always be zero on any early failures. */
size_t mcount = 0, dcount = 0;
if (flags & MDBX_MULTIPLE) { if (flags & MDBX_MULTIPLE) {
if (unlikely(!F_ISSET(mc->mc_db->md_flags, MDBX_DUPFIXED))) if (unlikely(!F_ISSET(mc->mc_db->md_flags, MDBX_DUPFIXED)))
return MDBX_INCOMPATIBLE; return MDBX_INCOMPATIBLE;
if (unlikely(data[1].iov_len >= INT_MAX)) dcount = data[1].iov_len;
return MDBX_EINVAL; if (unlikely(dcount < 2 || data->iov_len == 0))
dcount = (unsigned)data[1].iov_len; return MDBX_BAD_VALSIZE;
data[1].iov_len = 0; if (unlikely(mc->mc_db->md_xsize != data->iov_len) && mc->mc_db->md_xsize)
return MDBX_BAD_VALSIZE;
if (unlikely(dcount >
MAX_MAPSIZE / 2 / (BRANCH_NODEMAX(MAX_PAGESIZE) - NODESIZE))) {
/* checking for multiplication overflow */
if (unlikely(dcount > MAX_MAPSIZE / 2 / data->iov_len))
return MDBX_TOO_LARGE;
}
data[1].iov_len = 0 /* reset done item counter */;
} }
if (flags & MDBX_RESERVE) { if (flags & MDBX_RESERVE) {
@ -12094,8 +12100,8 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
data->iov_base = nullptr; data->iov_base = nullptr;
} }
nospill = flags & MDBX_NOSPILL; const unsigned nospill = flags & MDBX_NOSPILL;
flags &= ~MDBX_NOSPILL; flags -= nospill;
if (unlikely(mc->mc_txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED))) if (unlikely(mc->mc_txn->mt_flags & (MDBX_TXN_RDONLY | MDBX_TXN_BLOCKED)))
return (mc->mc_txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS return (mc->mc_txn->mt_flags & MDBX_TXN_RDONLY) ? MDBX_EACCESS
@ -12145,6 +12151,8 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
return MDBX_BAD_VALSIZE; return MDBX_BAD_VALSIZE;
case 4: case 4:
if (unlikely(3 & (uintptr_t)data->iov_base)) { if (unlikely(3 & (uintptr_t)data->iov_base)) {
if (unlikely(flags & MDBX_MULTIPLE))
return MDBX_BAD_VALSIZE;
/* copy instead of return error to avoid break compatibility */ /* copy instead of return error to avoid break compatibility */
aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base, aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base,
aligned_data.iov_len = 4); aligned_data.iov_len = 4);
@ -12153,6 +12161,8 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
break; break;
case 8: case 8:
if (unlikely(7 & (uintptr_t)data->iov_base)) { if (unlikely(7 & (uintptr_t)data->iov_base)) {
if (unlikely(flags & MDBX_MULTIPLE))
return MDBX_BAD_VALSIZE;
/* copy instead of return error to avoid break compatibility */ /* copy instead of return error to avoid break compatibility */
aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base, aligned_data.iov_base = memcpy(&aligned_databytes, data->iov_base,
aligned_data.iov_len = 8); aligned_data.iov_len = 8);
@ -12287,12 +12297,12 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
if (mc->mc_db->md_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) { if (mc->mc_db->md_flags & (MDBX_INTEGERDUP | MDBX_DUPFIXED)) {
assert(data->iov_len >= mc->mc_dbx->md_vlen_min && assert(data->iov_len >= mc->mc_dbx->md_vlen_min &&
data->iov_len <= mc->mc_dbx->md_vlen_max); data->iov_len <= mc->mc_dbx->md_vlen_max);
mc->mc_dbx->md_vlen_min = mc->mc_dbx->md_vlen_max = data->iov_len;
assert(mc->mc_xcursor != NULL); assert(mc->mc_xcursor != NULL);
mc->mc_db->md_xsize = mc->mc_xcursor->mx_db.md_xsize = mc->mc_db->md_xsize = mc->mc_xcursor->mx_db.md_xsize =
(unsigned)data->iov_len; (unsigned)(mc->mc_dbx->md_vlen_min = mc->mc_dbx->md_vlen_max =
mc->mc_xcursor->mx_dbx.md_klen_min = mc->mc_xcursor->mx_dbx.md_klen_max = mc->mc_xcursor->mx_dbx.md_klen_min =
data->iov_len; mc->mc_xcursor->mx_dbx.md_klen_max =
data->iov_len);
} }
*mc->mc_dbistate |= DBI_DIRTY; *mc->mc_dbistate |= DBI_DIRTY;
if ((mc->mc_db->md_flags & (MDBX_DUPSORT | MDBX_DUPFIXED)) == MDBX_DUPFIXED) if ((mc->mc_db->md_flags & (MDBX_DUPSORT | MDBX_DUPFIXED)) == MDBX_DUPFIXED)
@ -12639,9 +12649,9 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data,
rdata = data; rdata = data;
new_sub: new_sub:;
nflags = flags & NODE_ADD_FLAGS; unsigned nflags = flags & NODE_ADD_FLAGS;
nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->iov_len size_t nsize = IS_LEAF2(mc->mc_pg[mc->mc_top]) ? key->iov_len
: leaf_size(env, key, rdata); : leaf_size(env, key, rdata);
if (page_room(mc->mc_pg[mc->mc_top]) < nsize) { if (page_room(mc->mc_pg[mc->mc_top]) < nsize) {
if ((flags & (F_DUPDATA | F_SUBDATA)) == F_DUPDATA) if ((flags & (F_DUPDATA | F_SUBDATA)) == F_DUPDATA)