From 87586715524cfed9f94240a63112f4f0de9f2797 Mon Sep 17 00:00:00 2001 From: Conner Fromknecht Date: Fri, 3 Aug 2018 16:43:18 -0700 Subject: [PATCH] contractcourt/chain_arbitrator: fix potential shutdown race This commit fixes a potential race condition during shutdown, that could allow the chain arb's activeWatchers or activeChannels map to be modified while ranging over their contents. We fix this by copying the contents into new maps with the mutex held, before releasing the mutex and shutting down each watcher or channel arbitrator. --- contractcourt/chain_arbitrator.go | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/contractcourt/chain_arbitrator.go b/contractcourt/chain_arbitrator.go index 9ab11da8..97618d3a 100644 --- a/contractcourt/chain_arbitrator.go +++ b/contractcourt/chain_arbitrator.go @@ -448,12 +448,24 @@ func (c *ChainArbitrator) Stop() error { close(c.quit) + var ( + activeWatchers = make(map[wire.OutPoint]*chainWatcher) + activeChannels = make(map[wire.OutPoint]*ChannelArbitrator) + ) + + // Copy the current set of active watchers and arbitrators to shutdown. + // We don't want to hold the lock when shutting down each watcher or + // arbitrator individually, as they may need to acquire this mutex. c.Lock() - arbitrators := c.activeChannels - watchers := c.activeWatchers + for chanPoint, watcher := range c.activeWatchers { + activeWatchers[chanPoint] = watcher + } + for chanPoint, arbitrator := range c.activeChannels { + activeChannels[chanPoint] = arbitrator + } c.Unlock() - for chanPoint, watcher := range watchers { + for chanPoint, watcher := range activeWatchers { log.Tracef("Attempting to stop ChainWatcher(%v)", chanPoint) @@ -462,7 +474,7 @@ func (c *ChainArbitrator) Stop() error { "ChannelPoint(%v): %v", chanPoint, err) } } - for chanPoint, arbitrator := range arbitrators { + for chanPoint, arbitrator := range activeChannels { log.Tracef("Attempting to stop ChannelArbitrator(%v)", chanPoint)