Source file src/runtime/testdata/testgoroutineleakprofile/goker/cockroach10790.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a MIT
     3  // license that can be found in the LICENSE file.
     4  
     5  /*
     6   * Project: cockroach
     7   * Issue or PR  : https://github.com/cockroachdb/cockroach/pull/10790
     8   * Buggy version: 96b5452557ebe26bd9d85fe7905155009204d893
     9   * fix commit-id: f1a5c19125c65129b966fbdc0e6408e8df214aba
    10   * Flaky: 28/100
    11   * Description:
    12   *   It is possible that a message from ctxDone will make the function beginCmds
    13   * returns without draining the channel ch, so that goroutines created by anonymous
    14   * function will leak.
    15   */
    16  
    17  package main
    18  
    19  import (
    20  	"context"
    21  	"os"
    22  	"runtime/pprof"
    23  	"time"
    24  )
    25  
    26  func init() {
    27  	register("Cockroach10790", Cockroach10790)
    28  }
    29  
    30  type Replica_cockroach10790 struct {
    31  	chans   []chan bool
    32  }
    33  
    34  func (r *Replica_cockroach10790) beginCmds(ctx context.Context) {
    35  	ctxDone := ctx.Done()
    36  	for _, ch := range r.chans {
    37  		select {
    38  		case <-ch:
    39  		case <-ctxDone:
    40  			go func() { // G3
    41  				for _, ch := range r.chans {
    42  					<-ch
    43  				}
    44  			}()
    45  		}
    46  	}
    47  }
    48  
    49  func (r *Replica_cockroach10790) sendChans(ctx context.Context) {
    50  	for _, ch := range r.chans {
    51  		select {
    52  		case ch <- true:
    53  		case <-ctx.Done():
    54  			return
    55  		}
    56  	}
    57  }
    58  
    59  func NewReplica_cockroach10790() *Replica_cockroach10790 {
    60  	r := &Replica_cockroach10790{}
    61  	r.chans = append(r.chans, make(chan bool), make(chan bool))
    62  	return r
    63  }
    64  
    65  // Example of goroutine leak trace:
    66  //
    67  // G1              G2                G3                     helper goroutine
    68  //--------------------------------------------------------------------------------------
    69  // .							 .                                        r.sendChans()
    70  // r.beginCmds()   .                                        .
    71  // .               .                                        ch1 <-
    72  // <-ch1 <================================================> ch1 <-
    73  // .               .                                        select [ch2<-, <-ctx.Done()]
    74  // .               cancel()                                 .
    75  // .               <<done>>                                 [<-ctx.Done()] ==> return
    76  // .                                                        <<done>>
    77  // go func() [G3]                                           .
    78  // .                                 <-ch1
    79  //	------------------------------G3 leaks----------------------------------------------
    80  //
    81  
    82  func Cockroach10790() {
    83  	prof := pprof.Lookup("goroutineleak")
    84  	defer func() {
    85  		time.Sleep(100 * time.Millisecond)
    86  		prof.WriteTo(os.Stdout, 2)
    87  	}()
    88  
    89  	for i := 0; i < 100; i++ {
    90  		go func() {
    91  			r := NewReplica_cockroach10790()
    92  			ctx, cancel := context.WithCancel(context.Background())
    93  			go r.sendChans(ctx) // helper goroutine
    94  			go r.beginCmds(ctx) // G1
    95  			go cancel()         // G2
    96  		}()
    97  	}
    98  }
    99  

View as plain text