Skip to content

Commit

Permalink
Don't cure, immunize: ensure boost does not receive exceptions from m…
Browse files Browse the repository at this point in the history
…odify()

Current boost will delete an object from a multi_index_container if when
modifying that object, the functor throws an exception. This breaks the
undo infrastructure when it tries to undo the failed change, but the
object is missing. To prevent this, we catch the exception before it
reaches boost.
  • Loading branch information
nathanielhourt authored and abitmore committed Jul 21, 2018
1 parent db93b74 commit 0da5d96
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 4 deletions.
22 changes: 18 additions & 4 deletions libraries/db/include/graphene/db/generic_index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,24 @@ namespace graphene { namespace chain {

virtual void modify( const object& obj, const std::function<void(object&)>& m )override
{
assert( nullptr != dynamic_cast<const ObjectType*>(&obj) );
auto ok = _indices.modify( _indices.iterator_to( static_cast<const ObjectType&>(obj) ),
[&m]( ObjectType& o ){ m(o); } );
FC_ASSERT( ok, "Could not modify object, most likely a index constraint was violated" );
assert(nullptr != dynamic_cast<const ObjectType*>(&obj));
bool exception = false;
auto ok = _indices.modify(_indices.iterator_to(static_cast<const ObjectType&>(obj)),
[&m, &exception](ObjectType& o) {
try {
m(o);
} catch (fc::exception e) {
exception = true;
elog("Exception while modifying object: ${e} -- object may be corrupted",
("e", e));
} catch (...) {
exception = true;
elog("Unknown exception while modifying object");
}
}
);
FC_ASSERT(!exception, "Aborting for exception while modifying object");
FC_ASSERT(ok, "Could not modify object, most likely a index constraint was violated");
}

virtual void remove( const object& obj )override
Expand Down
26 changes: 26 additions & 0 deletions tests/tests/database_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,32 @@ BOOST_AUTO_TEST_CASE( undo_test )
}
}

/**
* Check that database modify() functors that throw do not get caught by boost, which will remove the object
*/
BOOST_AUTO_TEST_CASE(failed_modify_test)
{ try {
database db;
// Create dummy object
const auto& obj = db.create<account_balance_object>([](account_balance_object& obj) {
obj.owner = account_id_type(123);
});
account_balance_id_type obj_id = obj.id;
BOOST_CHECK_EQUAL(obj.owner.instance.value, 123);

// Modify dummy object, check that changes stick
db.modify(obj, [](account_balance_object& obj) {
obj.owner = account_id_type(234);
});
BOOST_CHECK_EQUAL(obj_id(db).owner.instance.value, 234);

// Throw exception when modifying object, check that object still exists after
BOOST_CHECK_THROW(db.modify(obj, [](account_balance_object& obj) {
throw 5;
}), fc::assert_exception);
BOOST_CHECK_NE(db.find_object(obj_id), nullptr);
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE( flat_index_test )
{ try {
ACTORS((sam));
Expand Down

0 comments on commit 0da5d96

Please sign in to comment.