diff --git a/src/api-cursor.c b/src/api-cursor.c index 4489a64f..4a506b41 100644 --- a/src/api-cursor.c +++ b/src/api-cursor.c @@ -712,22 +712,10 @@ int mdbx_cursor_put(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, MDBX_p if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); - /* Check this first so counter will always be zero on any early failures. */ if (unlikely(flags & MDBX_MULTIPLE)) { - if (unlikely(flags & MDBX_RESERVE)) - return LOG_IFERR(MDBX_EINVAL); - if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) - return LOG_IFERR(MDBX_INCOMPATIBLE); - const size_t dcount = data[1].iov_len; - if (unlikely(dcount < 2 || data->iov_len == 0)) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(mc->tree->dupfix_size != data->iov_len) && mc->tree->dupfix_size) - return LOG_IFERR(MDBX_BAD_VALSIZE); - if (unlikely(dcount > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { - /* checking for multiplication overflow */ - if (unlikely(dcount > MAX_MAPSIZE / 2 / data->iov_len)) - return LOG_IFERR(MDBX_TOO_LARGE); - } + rc = cursor_check_multiple(mc, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); } if (flags & MDBX_RESERVE) { diff --git a/src/api-txn-data.c b/src/api-txn-data.c index 2be54df8..cc0891cb 100644 --- a/src/api-txn-data.c +++ b/src/api-txn-data.c @@ -266,6 +266,19 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *key, MDBX_val *data, M rc = cursor_init(&cx.outer, txn, dbi); if (unlikely(rc != MDBX_SUCCESS)) return LOG_IFERR(rc); + + if (unlikely(flags & MDBX_MULTIPLE)) { + rc = cursor_check_multiple(&cx.outer, key, data, flags); + if (unlikely(rc != MDBX_SUCCESS)) + return LOG_IFERR(rc); + } + + if (flags & MDBX_RESERVE) { + if (unlikely(cx.outer.tree->flags & (MDBX_DUPSORT | MDBX_REVERSEDUP | MDBX_INTEGERDUP | MDBX_DUPFIXED))) + return LOG_IFERR(MDBX_INCOMPATIBLE); + data->iov_base = nullptr; + } + cx.outer.next = txn->cursors[dbi]; txn->cursors[dbi] = &cx.outer; diff --git a/src/cursor.c b/src/cursor.c index 9da14343..233c2246 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -1439,6 +1439,21 @@ insert_node:; return rc; } +int cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { + (void)key; + if (unlikely(flags & MDBX_RESERVE)) + return MDBX_EINVAL; + if (unlikely(!(mc->tree->flags & MDBX_DUPFIXED))) + return MDBX_INCOMPATIBLE; + const size_t number = data[1].iov_len; + if (unlikely(number > MAX_MAPSIZE / 2 / (BRANCH_NODE_MAX(MDBX_MAX_PAGESIZE) - NODESIZE))) { + /* checking for multiplication overflow */ + if (unlikely(number > MAX_MAPSIZE / 2 / data->iov_len)) + return MDBX_TOO_LARGE; + } + return MDBX_SUCCESS; +} + __hot int cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags) { cASSERT(mc, (mc->flags & z_inner) == 0); if (unlikely(key->iov_len > mc->clc->k.lmax || key->iov_len < mc->clc->k.lmin)) { diff --git a/src/cursor.h b/src/cursor.h index d8100999..d07be856 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -315,6 +315,9 @@ MDBX_INTERNAL MDBX_cursor *cursor_cpstk(const MDBX_cursor *csrc, MDBX_cursor *cd MDBX_INTERNAL int __must_check_result cursor_ops(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, const MDBX_cursor_op op); +MDBX_INTERNAL int __must_check_result cursor_check_multiple(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, + unsigned flags); + MDBX_INTERNAL int __must_check_result cursor_put_checklen(MDBX_cursor *mc, const MDBX_val *key, MDBX_val *data, unsigned flags);