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); }
|
try { functor.call(e->_obj); }
|
||||||
|
|
||||||
/* propagate exceptions while keeping registry consistent */
|
/* 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);
|
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
|
python
|
||||||
ram_fs_chunk
|
ram_fs_chunk
|
||||||
reconstructible
|
reconstructible
|
||||||
|
registry
|
||||||
report_rom
|
report_rom
|
||||||
resource_request
|
resource_request
|
||||||
resource_yield
|
resource_yield
|
||||||
|
Loading…
Reference in New Issue
Block a user