Skip to content
This repository was archived by the owner on Mar 22, 2023. It is now read-only.

Commit 2153423

Browse files
Merge pull request #984 from igchor/radix_use_after_free
radix_tree: fix use after free
2 parents d5c29f9 + 14a5c73 commit 2153423

File tree

2 files changed

+54
-2
lines changed

2 files changed

+54
-2
lines changed

include/libpmemobj++/experimental/radix_tree.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,6 +1802,10 @@ radix_tree<Key, Value, BytesView>::erase(const_iterator pos)
18021802
auto *leaf = pos.leaf_;
18031803
auto parent = leaf->parent;
18041804

1805+
/* there are more elements in the container */
1806+
if (parent)
1807+
++pos;
1808+
18051809
delete_persistent<radix_tree::leaf>(
18061810
persistent_ptr<radix_tree::leaf>(leaf));
18071811

@@ -1814,8 +1818,6 @@ radix_tree<Key, Value, BytesView>::erase(const_iterator pos)
18141818
return;
18151819
}
18161820

1817-
++pos;
1818-
18191821
/* It's safe to cast because we're inside non-const method. */
18201822
const_cast<tagged_node_ptr &>(*parent->find_child(leaf)) =
18211823
nullptr;

tests/radix/radix_basic.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,55 @@ test_inline_string_u8t_key(nvobj::pool<root> &pop)
847847
UT_ASSERT(OID_IS_NULL(pmemobj_first(pop.handle())));
848848
}
849849

850+
void
851+
test_remove_inserted(nvobj::pool<root> &pop)
852+
{
853+
const size_t NUM_ITER = 100;
854+
855+
auto r = pop.root();
856+
857+
nvobj::transaction::run(pop, [&] {
858+
r->radix_str = nvobj::make_persistent<container_string>();
859+
});
860+
861+
/* remove element which was just inserted */
862+
nvobj::transaction::run(pop, [&] {
863+
for (size_t i = 0; i < NUM_ITER; i++) {
864+
UT_ASSERT(r->radix_str
865+
->emplace(std::to_string(i),
866+
std::to_string(i))
867+
.second);
868+
UT_ASSERT(r->radix_str->erase(std::to_string(i)));
869+
}
870+
});
871+
872+
/* insert some initial elements */
873+
nvobj::transaction::run(pop, [&] {
874+
for (size_t i = 0; i < 5; i++)
875+
UT_ASSERT(r->radix_str
876+
->emplace("init" + std::to_string(i),
877+
std::to_string(i))
878+
.second);
879+
});
880+
881+
/* remove element which was just inserted */
882+
nvobj::transaction::run(pop, [&] {
883+
for (size_t i = 0; i < NUM_ITER; i++) {
884+
UT_ASSERT(r->radix_str
885+
->emplace(std::to_string(i),
886+
std::to_string(i))
887+
.second);
888+
UT_ASSERT(r->radix_str->erase(std::to_string(i)));
889+
}
890+
});
891+
892+
nvobj::transaction::run(pop, [&] {
893+
nvobj::delete_persistent<container_string>(r->radix_str);
894+
});
895+
896+
UT_ASSERT(OID_IS_NULL(pmemobj_first(pop.handle())));
897+
}
898+
850899
static void
851900
test(int argc, char *argv[])
852901
{
@@ -880,6 +929,7 @@ test(int argc, char *argv[])
880929
test_compression(pop);
881930
test_inline_string_u8t_key(pop);
882931

932+
test_remove_inserted(pop);
883933
pop.close();
884934
}
885935

0 commit comments

Comments
 (0)