Skip to content

Commit eec147d

Browse files
committed
Only finalize mapped all from Go when map entry exists
There was still a double finalization race, detected by the panic introduced by the previous commit. If setErr() is called during client teardown, all currently managed calls will be errored and finalized, and the calls map set to nil. Unfortunately, Client.Go was again finalizing the call even after setErr released the calls mutex, because it had a another variable pointing to it. To fix this race, look up the call entry in the map and only finalize and delete it when it present.
1 parent 7a86b28 commit eec147d

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

rpc.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -501,11 +501,16 @@ func (c *Client) Go(ctx context.Context, method string, result interface{}, done
501501
if err != nil {
502502
// This may be called concurrently with out() -> setErr(), so
503503
// finalize the error under the client mutex to prevent double
504-
// finalization.
504+
// finalization. Only call finalization if the map and entry
505+
// still exists (as setErr() will nil the map it after client
506+
// teardown), otherwise we will finalize the call again.
505507
c.callMu.Lock()
506-
delete(c.calls, id)
507-
call.err = err
508-
call.finalize()
508+
call2, ok := c.calls[id]
509+
if ok {
510+
delete(c.calls, id)
511+
call2.err = err
512+
call2.finalize()
513+
}
509514
c.callMu.Unlock()
510515
}
511516
return call

0 commit comments

Comments
 (0)