Skip to content

Commit c56ad38

Browse files
committed
Dial: fix goroutine leak on cancelled context
The goroutine performing the banner message exchange would block on the error channel before returning, but the error channel was not drained if the context is cancelled before the error is sent to the error channel.
1 parent 53a2e44 commit c56ad38

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

Diff for: dial.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ func Dial(dialCtx context.Context, endpoint Endpoint) (*SSHConn , error) {
186186

187187
confErrChan := make(chan error)
188188
go func() {
189+
defer close(confErrChan)
189190
var buf bytes.Buffer
190191
if _, err := io.CopyN(&buf, cmd, int64(len(banner_msg))); err != nil {
191192
confErrChan <- &SSHError{err, "read banner"}
@@ -208,13 +209,22 @@ func Dial(dialCtx context.Context, endpoint Endpoint) (*SSHConn , error) {
208209
confErrChan <- &SSHError{err, "send begin message"}
209210
return
210211
}
211-
close(confErrChan)
212212
}()
213213

214214
select {
215215
case <-dialCtx.Done():
216+
216217
commandCancel()
218+
// cancelling will make one of the calls in above goroutine fail,
219+
// and the goroutine will send the error to confErrChan
220+
//
221+
// ignore the error and return the cancellation cause
222+
223+
// draining always terminates because we know the channel is always closed
224+
for _ = range confErrChan {}
225+
217226
return nil, dialCtx.Err()
227+
218228
case err := <-confErrChan:
219229
if err != nil {
220230
commandCancel()

0 commit comments

Comments
 (0)