mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-30 11:29:19 +08:00
mdbx: refine/fix handling MDBX_MULTIPLE in the mdbx_cursor_put().
Change-Id: I06ac9d73cec01afb492b5c663acf310d19e4900b
This commit is contained in:
parent
426d207fc4
commit
89dba59ce2
42
src/core.c
42
src/core.c
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user