From 99e431c8daa8bc265e47e41b4ea7e94549caa653 Mon Sep 17 00:00:00 2001 From: Jason Volk Date: Mon, 6 Nov 2017 12:10:55 -0800 Subject: [PATCH] ircd::ctx: Further fix and clarify the POST/DETACH leak potential. --- include/ircd/ctx/context.h | 1 + ircd/ctx.cc | 27 +++++++++++++++++++-------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/ircd/ctx/context.h b/include/ircd/ctx/context.h index bfe425664..b097b9792 100644 --- a/include/ircd/ctx/context.h +++ b/include/ircd/ctx/context.h @@ -60,6 +60,7 @@ namespace ircd::ctx struct ircd::ctx::context { enum flags + :uint { POST = 0x01, ///< Defers spawn with an ios.post() DISPATCH = 0x02, ///< Defers spawn with an ios.dispatch() (possibly) diff --git a/ircd/ctx.cc b/ircd/ctx.cc index 6ecc02cfb..9122b5768 100644 --- a/ircd/ctx.cc +++ b/ircd/ctx.cc @@ -540,20 +540,29 @@ ircd::ctx::context::context(const char *const &name, function func) :c{std::make_unique(name, stack_sz, flags, ircd::ios)} { - // The profiler is told about the spawn request here, not inside the closure - // which is probably the same event-slice as event::CUR_ENTER and not as useful. - mark(prof::event::SPAWN); - auto spawn { std::bind(&ircd::ctx::spawn, c.get(), std::move(func)) }; - const unwind release{[this, &flags] + // The profiler is told about the spawn request here, not inside the closure + // which is probably the same event-slice as event::CUR_ENTER and not as useful. + mark(prof::event::SPAWN); + + // When the user passes the DETACH flag we want to release the unique_ptr + // of the ctx if and only if that ctx is committed to freeing itself. Our + // commitment ends at the 180 of this function. If no exception was thrown + // we expect the context to be committed to entry. If the POST flag is + // supplied and it gets lost in the asio queue it will not be entered, and + // will not be able to free itself; that will leak. + const unwind::nominal release { - if(flags & DETACH) - this->c.release(); - }}; + [this, &flags] + { + if(flags & context::DETACH) + this->detach(); + } + }; if(flags & POST) { @@ -644,6 +653,7 @@ ircd::ctx::context::join() return; mark(prof::event::JOIN); + assert(bool(c)); assert(!c->adjoindre); c->adjoindre = &cur(); // Set the target context to notify this context when it finishes wait(); @@ -653,6 +663,7 @@ ircd::ctx::context::join() ircd::ctx::ctx * ircd::ctx::context::detach() { + assert(bool(c)); c->flags |= DETACH; return c.release(); }