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.
This commit is contained in:
Conner Fromknecht 2018-08-03 16:43:18 -07:00
parent f0f5e11b82
commit 8758671552
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7

@ -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)