mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 21:27:56 +00:00
base: exception safety during registry iteration
This patch fixes a problem in the non-const 'for_each' method of the 'Registry' data structure. If an exception was thrown from within the functor of the 'for_each' operation, the not yet processed items of the registry were dropped from the registry, which is not expected.
This commit is contained in:
parent
ccf6b237bb
commit
c270e4fb30
27
repos/base/run/registry.run
Normal file
27
repos/base/run/registry.run
Normal file
@ -0,0 +1,27 @@
|
||||
build "core init test/registry"
|
||||
|
||||
create_boot_directory
|
||||
|
||||
install_config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="CPU"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> </any-service>
|
||||
</default-route>
|
||||
<default caps="50"/>
|
||||
<start name="test-registry">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
build_boot_image "core ld.lib.so init test-registry"
|
||||
|
||||
append qemu_args "-nographic "
|
||||
|
||||
run_genode_until ".*child \"test-registry\" exited with exit value 0.*\n" 20
|
@ -134,7 +134,21 @@ void Registry_base::_for_each(Untyped_functor &functor)
|
||||
try { functor.call(e->_obj); }
|
||||
|
||||
/* propagate exceptions while keeping registry consistent */
|
||||
catch (...) { at = _processed(notify, processed, *e, at); throw; }
|
||||
catch (...) {
|
||||
|
||||
/* handle current element */
|
||||
at = _processed(notify, processed, *e, at);
|
||||
|
||||
/* handle the remaining elements without invoking the functor */
|
||||
while (Element *e = _elements.first()) {
|
||||
_elements.remove(e);
|
||||
at = _processed(notify, processed, *e, at);
|
||||
};
|
||||
_elements = processed;
|
||||
|
||||
/* propagate exception to caller */
|
||||
throw;
|
||||
}
|
||||
|
||||
at = _processed(notify, processed, *e, at);
|
||||
}
|
||||
|
79
repos/base/src/test/registry/main.cc
Normal file
79
repos/base/src/test/registry/main.cc
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* \brief Test for 'Registry' data structure
|
||||
* \author Norman Feske
|
||||
* \date 2018-08-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2018 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/registry.h>
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
|
||||
|
||||
/*
|
||||
* Check that an exception that occurs during the iteration over
|
||||
* registry items does not affect the registry content.
|
||||
*/
|
||||
static void test_exception_during_for_each()
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
struct Item : Interface
|
||||
{
|
||||
typedef String<10> Name;
|
||||
Name const name;
|
||||
|
||||
Item(Name const &name) : name(name) { }
|
||||
|
||||
class Invalid : Exception { };
|
||||
|
||||
void visit()
|
||||
{
|
||||
if (name == "second")
|
||||
throw Invalid();
|
||||
}
|
||||
};
|
||||
|
||||
Registry<Registered<Item> > items { };
|
||||
|
||||
Registered<Item> first (items, "first");
|
||||
Registered<Item> second(items, "second");
|
||||
Registered<Item> third (items, "third");
|
||||
|
||||
auto num_items = [&] () {
|
||||
unsigned cnt = 0;
|
||||
items.for_each([&] (Item &) { cnt++; });
|
||||
return cnt;
|
||||
};
|
||||
|
||||
unsigned const num_items_before_exception = num_items();
|
||||
|
||||
try {
|
||||
items.for_each([&] (Item &item) {
|
||||
/* second item throws an exception */
|
||||
item.visit();
|
||||
});
|
||||
}
|
||||
catch (Item::Invalid) { log("exception occurred (expected)"); };
|
||||
|
||||
unsigned const num_items_after_exception = num_items();
|
||||
|
||||
struct Failed : Exception { };
|
||||
if (num_items_before_exception != num_items_after_exception)
|
||||
throw Failed();
|
||||
}
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
test_exception_during_for_each();
|
||||
|
||||
env.parent().exit(0);
|
||||
}
|
3
repos/base/src/test/registry/target.mk
Normal file
3
repos/base/src/test/registry/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-registry
|
||||
SRC_CC = main.cc
|
||||
LIBS += base
|
@ -71,6 +71,7 @@ pthread
|
||||
python
|
||||
ram_fs_chunk
|
||||
reconstructible
|
||||
registry
|
||||
report_rom
|
||||
resource_request
|
||||
resource_yield
|
||||
|
Loading…
Reference in New Issue
Block a user