mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-13 22:23:45 +00:00
core: do not destroy in object pool's apply scope
Destroying an object within the scope of a lambda/functor executed in the object pool's apply function leads potentially to memory corruption. Within the scope the corresponding object is locked and unlocked when leaving the scope. Therefore, it is illegal to free the object's memory meanwhile. This commit eliminates several places in core that destroyed wrongly in the object pool's scope. Fix #1713
This commit is contained in:
parent
6616bd4593
commit
b585583ec7
@ -153,13 +153,15 @@ void Cap_session_component::free(Native_capability cap)
|
||||
/* proof whether the capability was created by this cap_session */
|
||||
if (static_cast<Core_cap_index*>(cap.idx())->session() != this) return;
|
||||
|
||||
_pool.apply(cap, [this] (Entry *e) {
|
||||
Entry * entry;
|
||||
_pool.apply(cap, [&] (Entry *e) {
|
||||
entry = e;
|
||||
if (e) {
|
||||
_pool.remove(e);
|
||||
destroy(_md_alloc, e);
|
||||
} else
|
||||
PWRN("Could not find capability to be deleted");
|
||||
});
|
||||
if (entry) destroy(_md_alloc, entry);
|
||||
}
|
||||
|
||||
|
||||
|
@ -190,7 +190,7 @@ namespace Genode {
|
||||
* by themselves and call this function to perform the actual
|
||||
* killing.
|
||||
*/
|
||||
void _unsynchronized_kill_thread(Cpu_thread_component *thread);
|
||||
void _unsynchronized_kill_thread(Thread_capability cap);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -52,16 +52,18 @@ Signal_receiver_capability Signal_session_component::alloc_receiver()
|
||||
void Signal_session_component::free_receiver(Signal_receiver_capability cap)
|
||||
{
|
||||
/* look up ressource info */
|
||||
Receiver * receiver;
|
||||
auto lambda = [&] (Receiver *r) {
|
||||
if (!r) {
|
||||
receiver = r;
|
||||
if (!receiver) {
|
||||
PERR("unknown signal receiver");
|
||||
throw Kill_receiver_failed();
|
||||
}
|
||||
/* release resources */
|
||||
_receivers.remove(r);
|
||||
destroy(&_receivers_slab, r);
|
||||
_receivers.remove(receiver);
|
||||
};
|
||||
_receivers.apply(cap, lambda);
|
||||
destroy(&_receivers_slab, receiver);
|
||||
}
|
||||
|
||||
|
||||
@ -93,16 +95,18 @@ Signal_session_component::alloc_context(Signal_receiver_capability src,
|
||||
void Signal_session_component::free_context(Signal_context_capability cap)
|
||||
{
|
||||
/* look up ressource info */
|
||||
Context * context;
|
||||
auto lambda = [&] (Context *c) {
|
||||
if (!c) {
|
||||
context = c;
|
||||
if (!context) {
|
||||
PERR("unknown signal context");
|
||||
throw Kill_context_failed();
|
||||
}
|
||||
/* release resources */
|
||||
_contexts.remove(c);
|
||||
destroy(&_contexts_slab, c);
|
||||
_contexts.remove(context);
|
||||
};
|
||||
_contexts.apply(cap, lambda);
|
||||
destroy(&_contexts_slab, context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -183,7 +183,7 @@ namespace Genode {
|
||||
* by themselves and call this function to perform the actual
|
||||
* killing.
|
||||
*/
|
||||
void _unsynchronized_kill_thread(Cpu_thread_component *thread);
|
||||
void _unsynchronized_kill_thread(Thread_capability cap);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -194,7 +194,7 @@ namespace Genode {
|
||||
* by themselves and call this function to perform the actual
|
||||
* killing.
|
||||
*/
|
||||
void _unsynchronized_kill_thread(Cpu_thread_component *thread);
|
||||
void _unsynchronized_kill_thread(Thread_capability cap);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -87,20 +87,22 @@ Signal_context_capability Signal_session_component::alloc_context(long imprint)
|
||||
|
||||
void Signal_session_component::free_context(Signal_context_capability context_cap)
|
||||
{
|
||||
auto lambda = [&] (Signal_context_component *context) {
|
||||
if (!context) {
|
||||
PWRN("%p - specified signal-context capability has wrong type %lx",
|
||||
this, context_cap.local_name());
|
||||
return;
|
||||
}
|
||||
|
||||
_signal_queue.remove(context);
|
||||
destroy(&_contexts_slab, context);
|
||||
|
||||
Nova::revoke(Nova::Obj_crd(context_cap.local_name(), 0));
|
||||
cap_map()->remove(context_cap.local_name(), 0);
|
||||
Signal_context_component *context;
|
||||
auto lambda = [&] (Signal_context_component *c) {
|
||||
context = c;
|
||||
if (context) _signal_queue.remove(context);
|
||||
};
|
||||
_signal_queue.apply(context_cap, lambda);
|
||||
|
||||
if (!context) {
|
||||
PWRN("%p - specified signal-context capability has wrong type %lx",
|
||||
this, context_cap.local_name());
|
||||
return;
|
||||
}
|
||||
destroy(&_contexts_slab, context);
|
||||
|
||||
Nova::revoke(Nova::Obj_crd(context_cap.local_name(), 0));
|
||||
cap_map()->remove(context_cap.local_name(), 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -83,9 +83,14 @@ Thread_capability Cpu_session_component::create_thread(size_t weight,
|
||||
}
|
||||
|
||||
|
||||
void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *thread)
|
||||
void Cpu_session_component::_unsynchronized_kill_thread(Thread_capability thread_cap)
|
||||
{
|
||||
_thread_ep->dissolve(thread);
|
||||
Cpu_thread_component *thread;
|
||||
_thread_ep->apply(thread_cap, [&] (Cpu_thread_component *t) {
|
||||
if ((thread = t)) _thread_ep->dissolve(thread); });
|
||||
|
||||
if (!thread) return;
|
||||
|
||||
_thread_list.remove(thread);
|
||||
|
||||
_trace_sources.remove(thread->trace_source());
|
||||
@ -94,8 +99,10 @@ void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *th
|
||||
|
||||
_decr_weight(thread->weight());
|
||||
|
||||
Lock::Guard lock_guard(_thread_alloc_lock);
|
||||
destroy(&_thread_alloc, thread);
|
||||
{
|
||||
Lock::Guard lock_guard(_thread_alloc_lock);
|
||||
destroy(&_thread_alloc, thread);
|
||||
}
|
||||
|
||||
_trace_control_area.free(trace_control_index);
|
||||
}
|
||||
@ -103,13 +110,9 @@ void Cpu_session_component::_unsynchronized_kill_thread(Cpu_thread_component *th
|
||||
|
||||
void Cpu_session_component::kill_thread(Thread_capability thread_cap)
|
||||
{
|
||||
auto lambda = [this] (Cpu_thread_component *thread) {
|
||||
if (!thread) return;
|
||||
Lock::Guard lock_guard(_thread_list_lock);
|
||||
|
||||
Lock::Guard lock_guard(_thread_list_lock);
|
||||
_unsynchronized_kill_thread(thread);
|
||||
};
|
||||
_thread_ep->apply(thread_cap, lambda);
|
||||
_unsynchronized_kill_thread(thread_cap);
|
||||
}
|
||||
|
||||
|
||||
@ -469,7 +472,7 @@ void Cpu_session_component::_deinit_threads()
|
||||
*/
|
||||
|
||||
for (Cpu_thread_component *thread; (thread = _thread_list.first()); )
|
||||
_unsynchronized_kill_thread(thread);
|
||||
_unsynchronized_kill_thread(thread->cap());
|
||||
}
|
||||
|
||||
|
||||
|
@ -230,7 +230,7 @@ namespace Genode {
|
||||
* by themselves and call this function to perform the actual
|
||||
* killing.
|
||||
*/
|
||||
void _unsynchronized_kill_thread(Cpu_thread_component *thread);
|
||||
void _unsynchronized_kill_thread(Thread_capability cap);
|
||||
|
||||
public:
|
||||
|
||||
|
@ -81,7 +81,7 @@ namespace Genode {
|
||||
/**
|
||||
* Free dataspace
|
||||
*/
|
||||
void _free_ds(Dataspace_component *ds);
|
||||
void _free_ds(Dataspace_capability ds_cap);
|
||||
|
||||
/**
|
||||
* Transfer quota to another RAM session
|
||||
|
@ -35,31 +35,37 @@ addr_t Ram_session_component::phys_addr(Ram_dataspace_capability ds)
|
||||
}
|
||||
|
||||
|
||||
void Ram_session_component::_free_ds(Dataspace_component *ds)
|
||||
void Ram_session_component::_free_ds(Dataspace_capability ds_cap)
|
||||
{
|
||||
if (!ds) return;
|
||||
if (!ds->owner(this)) return;
|
||||
Dataspace_component *ds;
|
||||
_ds_ep->apply(ds_cap, [&] (Dataspace_component *c)
|
||||
{
|
||||
ds = c;
|
||||
|
||||
size_t ds_size = ds->size();
|
||||
if (!ds) return;
|
||||
if (!ds->owner(this)) return;
|
||||
|
||||
/* tell entry point to forget the dataspace */
|
||||
_ds_ep->dissolve(ds);
|
||||
size_t ds_size = ds->size();
|
||||
|
||||
/* remove dataspace from all RM sessions */
|
||||
ds->detach_from_rm_sessions();
|
||||
/* tell entry point to forget the dataspace */
|
||||
_ds_ep->dissolve(ds);
|
||||
|
||||
/* destroy native shared memory representation */
|
||||
_revoke_ram_ds(ds);
|
||||
/* remove dataspace from all RM sessions */
|
||||
ds->detach_from_rm_sessions();
|
||||
|
||||
/* free physical memory that was backing the dataspace */
|
||||
_ram_alloc->free((void *)ds->phys_addr(), ds_size);
|
||||
/* destroy native shared memory representation */
|
||||
_revoke_ram_ds(ds);
|
||||
|
||||
/* free physical memory that was backing the dataspace */
|
||||
_ram_alloc->free((void *)ds->phys_addr(), ds_size);
|
||||
|
||||
/* adjust payload */
|
||||
Lock::Guard lock_guard(_ref_members_lock);
|
||||
_payload -= ds_size;
|
||||
});
|
||||
|
||||
/* call dataspace destructors and free memory */
|
||||
destroy(&_ds_slab, ds);
|
||||
|
||||
/* adjust payload */
|
||||
Lock::Guard lock_guard(_ref_members_lock);
|
||||
_payload -= ds_size;
|
||||
}
|
||||
|
||||
|
||||
@ -218,15 +224,8 @@ Ram_dataspace_capability Ram_session_component::alloc(size_t ds_size, Cache_attr
|
||||
}
|
||||
|
||||
|
||||
void Ram_session_component::free(Ram_dataspace_capability ds_cap)
|
||||
{
|
||||
auto lambda = [this] (Dataspace_component *ds) {
|
||||
if (!ds) return;
|
||||
_free_ds(ds);
|
||||
};
|
||||
|
||||
_ds_ep->apply(ds_cap, lambda);
|
||||
}
|
||||
void Ram_session_component::free(Ram_dataspace_capability ds_cap) {
|
||||
_free_ds(ds_cap); }
|
||||
|
||||
|
||||
int Ram_session_component::ref_account(Ram_session_capability ram_session_cap)
|
||||
@ -291,7 +290,8 @@ Ram_session_component::Ram_session_component(Rpc_entrypoint *ds_ep,
|
||||
Ram_session_component::~Ram_session_component()
|
||||
{
|
||||
/* destroy all dataspaces */
|
||||
for (Dataspace_component *ds; (ds = _ds_slab()->first_object()); _free_ds(ds));
|
||||
for (Dataspace_component *ds; (ds = _ds_slab()->first_object());
|
||||
_free_ds(ds->cap()));
|
||||
|
||||
if (_payload != 0)
|
||||
PWRN("Remaining payload of %zu in ram session to destroy", _payload);
|
||||
|
@ -71,15 +71,17 @@ Signal_context_capability Signal_session_component::alloc_context(long imprint)
|
||||
|
||||
void Signal_session_component::free_context(Signal_context_capability context_cap)
|
||||
{
|
||||
_context_ep->apply(context_cap, [this] (Signal_context_component *context) {
|
||||
Signal_context_component *context;
|
||||
_context_ep->apply(context_cap, [&] (Signal_context_component *c) {
|
||||
context = c;
|
||||
if (!context) {
|
||||
PWRN("specified signal-context capability has wrong type");
|
||||
return;
|
||||
}
|
||||
|
||||
_context_ep->dissolve(context);
|
||||
destroy(&_contexts_slab, context);
|
||||
});
|
||||
destroy(&_contexts_slab, context);
|
||||
}
|
||||
|
||||
|
||||
|
@ -484,10 +484,10 @@ void Lx::backend_free(Genode::Ram_dataspace_capability cap)
|
||||
auto lambda = [&] (Memory_object_base *o) {
|
||||
object = o;
|
||||
if (object) {
|
||||
o->free();
|
||||
memory_pool.remove(o);
|
||||
object->free();
|
||||
memory_pool.remove(object);
|
||||
}
|
||||
};
|
||||
memory_pool.apply(cap, lambda);
|
||||
destroy(env()->heap(), object);
|
||||
if (object) destroy(env()->heap(), object);
|
||||
}
|
||||
|
@ -559,8 +559,10 @@ namespace Platform {
|
||||
|
||||
void release_device(Device_capability device_cap)
|
||||
{
|
||||
auto lambda = [&] (Device_component *device)
|
||||
Device_component * device;
|
||||
auto lambda = [&] (Device_component *d)
|
||||
{
|
||||
device = d;
|
||||
if (!device)
|
||||
return;
|
||||
|
||||
@ -573,15 +575,17 @@ namespace Platform {
|
||||
|
||||
_device_list.remove(device);
|
||||
_ep->dissolve(device);
|
||||
|
||||
if (device->config().valid())
|
||||
destroy(_device_slab, device);
|
||||
else
|
||||
destroy(_md_alloc, device);
|
||||
};
|
||||
|
||||
/* lookup device component for previous device */
|
||||
_ep->apply(device_cap, lambda);
|
||||
|
||||
if (!device) return;
|
||||
|
||||
if (device->config().valid())
|
||||
destroy(_device_slab, device);
|
||||
else
|
||||
destroy(_md_alloc, device);
|
||||
}
|
||||
|
||||
Genode::Io_mem_dataspace_capability assign_device(Device_component * device)
|
||||
|
Loading…
x
Reference in New Issue
Block a user