Skip to content

Commit 5dc37dc

Browse files
committed
datastore: fix out-of-bounds index in snapshots BTree
1 parent f81ca64 commit 5dc37dc

File tree

1 file changed

+29
-20
lines changed
  • silkworm/db/datastore/snapshots/btree

1 file changed

+29
-20
lines changed

silkworm/db/datastore/snapshots/btree/btree.cpp

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,23 +24,16 @@ BTree::BTree(
2424

2525
using CompareResult = std::pair<int, BytesOrByteView>;
2626

27-
static CompareResult compare_key(
27+
static std::optional<CompareResult> compare_key(
2828
ByteView key,
2929
BTree::DataIndex key_index,
3030
const BTree::KeyValueIndex& index) {
3131
auto data_key = index.lookup_key(key_index);
32-
ensure(data_key.has_value(), [&] { return "out-of-bounds key=" + to_hex(key) + " data_index=" + std::to_string(key_index); });
32+
if (!data_key) {
33+
return std::nullopt;
34+
}
3335
int cmp = ByteView{*data_key}.compare(key);
34-
return {cmp, std::move(*data_key)};
35-
}
36-
37-
static BTree::KeyValueIndex::LookupResult lookup_key_value(
38-
ByteView key,
39-
BTree::DataIndex key_index,
40-
const BTree::KeyValueIndex& index) {
41-
auto result = index.lookup_key_value(key_index, key);
42-
ensure(result.has_value(), [&] { return "out-of-bounds key=" + to_hex(key) + " data_index=" + std::to_string(key_index); });
43-
return std::move(*result);
36+
return CompareResult{cmp, std::move(*data_key)};
4437
}
4538

4639
BTree::SeekResult BTree::seek(ByteView seek_key, const KeyValueIndex& index) {
@@ -55,8 +48,12 @@ BTree::SeekResult BTree::seek(ByteView seek_key, const KeyValueIndex& index) {
5548
auto [_, left_index, right_index] = binary_search_in_cache(seek_key); // left_index == right_index when key is found
5649
uint64_t median = 0;
5750
while (left_index < right_index) {
58-
if (right_index - left_index <= kDefaultBtreeStartSkip) { // found small range, faster to scan now
59-
const auto [cmp, key] = compare_key(seek_key, left_index, index);
51+
if (right_index - left_index <= kDefaultBtreeStartSkip) { // found a small range, faster to scan now
52+
const auto cmp_result = compare_key(seek_key, left_index, index);
53+
if (!cmp_result) {
54+
return {/*found=*/false, {}, {}, 0};
55+
}
56+
const auto [cmp, key] = *cmp_result;
6057
if (cmp == 0) {
6158
right_index = left_index;
6259
break;
@@ -71,7 +68,11 @@ BTree::SeekResult BTree::seek(ByteView seek_key, const KeyValueIndex& index) {
7168
break;
7269
}
7370
median = (left_index + right_index) >> 1;
74-
const auto [cmp, key] = compare_key(seek_key, median, index);
71+
const auto cmp_result = compare_key(seek_key, median, index);
72+
if (!cmp_result) {
73+
return {/*found=*/false, {}, {}, 0};
74+
}
75+
const auto [cmp, key] = *cmp_result;
7576
if (cmp == 0) {
7677
left_index = right_index = median;
7778
break;
@@ -107,7 +108,7 @@ std::optional<BytesOrByteView> BTree::get(ByteView key, const KeyValueIndex& ind
107108
}
108109
auto [_, left_index, right_index] = binary_search_in_cache(key); // left_index == right_index when key is found
109110
while (left_index < right_index) {
110-
if (right_index - left_index <= kDefaultBtreeStartSkip) { // found small range, faster to scan now
111+
if (right_index - left_index <= kDefaultBtreeStartSkip) { // found a small range, faster to scan now
111112
auto value = index.advance_key_value(left_index, key, right_index - left_index);
112113
if (!value) {
113114
left_index = right_index;
@@ -116,7 +117,8 @@ std::optional<BytesOrByteView> BTree::get(ByteView key, const KeyValueIndex& ind
116117
return value;
117118
}
118119
const uint64_t median = (left_index + right_index) >> 1;
119-
auto [cmp, optional_v] = lookup_key_value(key, median, index);
120+
const auto lookup_result = index.lookup_key_value(median, key);
121+
const auto [cmp, optional_v] = *lookup_result;
120122
if (cmp == 0) {
121123
SILKWORM_ASSERT(optional_v);
122124
return optional_v;
@@ -127,7 +129,8 @@ std::optional<BytesOrByteView> BTree::get(ByteView key, const KeyValueIndex& ind
127129
left_index = median + 1;
128130
}
129131
}
130-
auto [cmp, optional_v] = lookup_key_value(key, left_index, index);
132+
const auto lookup_result = index.lookup_key_value(left_index, key);
133+
const auto [cmp, optional_v] = *lookup_result;
131134
if (cmp != 0) {
132135
return std::nullopt;
133136
}
@@ -157,7 +160,9 @@ void BTree::warmup(const KeyValueIndex& index) {
157160
const size_t step = num_nodes_ < fanout_ ? 1 : fanout_; // cache all keys if less than M
158161
for (size_t i{step}; i < num_nodes_; i += step) {
159162
const size_t data_index = i - 1;
160-
auto [_, key] = compare_key({}, data_index, index);
163+
auto cmp_result = compare_key({}, data_index, index);
164+
if (!cmp_result) continue;
165+
auto [_, key] = *cmp_result;
161166
cache_.emplace_back(Node{data_index, Bytes{key}});
162167
cached_bytes += sizeof(Node) + ByteView{key}.size();
163168
}
@@ -185,7 +190,11 @@ BTree::Nodes BTree::decode_nodes(std::span<uint8_t> encoded_nodes) {
185190

186191
void BTree::check_against_data_keys(const KeyValueIndex& index) {
187192
for (const auto& node : cache_) {
188-
const auto [cmp, key] = compare_key(node.key, node.key_index, index);
193+
const auto cmp_result = compare_key(node.key, node.key_index, index);
194+
ensure(cmp_result.has_value(), [&] {
195+
return "out-of-bounds key=" + to_hex(node.key) + " data_index=" + std::to_string(node.key_index);
196+
});
197+
const auto [cmp, key] = *cmp_result;
189198
ensure(cmp == 0, [&]() {
190199
return "key mismatch node.key=" + to_hex(node.key) +
191200
" key=" + to_hex(key) +

0 commit comments

Comments
 (0)