Source file src/cmd/cgo/internal/testsanitizers/testdata/tsan_tracebackctxt/main.go

     1  // Copyright 2025 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  /*
     8  // Defined in tracebackctxt_c.c.
     9  extern void C1(void);
    10  extern void C2(void);
    11  extern void tcContext(void*);
    12  extern void tcTraceback(void*);
    13  extern void tcSymbolizer(void*);
    14  */
    15  import "C"
    16  
    17  import (
    18  	"fmt"
    19  	"runtime"
    20  	"sync"
    21  	"unsafe"
    22  )
    23  
    24  // Regression test for https://go.dev/issue/73949. TSAN should not report races
    25  // on writes to the argument passed to the symbolizer function.
    26  //
    27  // Triggering this race requires calls to the symbolizer function with the same
    28  // argument pointer on multiple threads. The runtime passes a stack variable to
    29  // this function, so that means we need to get a single goroutine to execute on
    30  // two threads, calling the symbolizer function on each.
    31  //
    32  // runtime.CallersFrames / Next will call the symbolizer function (if there are
    33  // C frames). So the approach here is, with GOMAXPROCS=2, have 2 goroutines
    34  // that use CallersFrames over and over, both frequently calling Gosched in an
    35  // attempt to get picked up by the other P.
    36  
    37  var tracebackOK bool
    38  
    39  func main() {
    40  	runtime.GOMAXPROCS(2)
    41  	runtime.SetCgoTraceback(0, unsafe.Pointer(C.tcTraceback), unsafe.Pointer(C.tcContext), unsafe.Pointer(C.tcSymbolizer))
    42  	C.C1()
    43  	if tracebackOK {
    44  		fmt.Println("OK")
    45  	}
    46  }
    47  
    48  //export G1
    49  func G1() {
    50  	C.C2()
    51  }
    52  
    53  //export G2
    54  func G2() {
    55  	pc := make([]uintptr, 32)
    56  	n := runtime.Callers(0, pc)
    57  
    58  	var wg sync.WaitGroup
    59  	for range 2 {
    60  		wg.Go(func() {
    61  			for range 1000 {
    62  				cf := runtime.CallersFrames(pc[:n])
    63  				var frames []runtime.Frame
    64  				for {
    65  					frame, more := cf.Next()
    66  					frames = append(frames, frame)
    67  					if !more {
    68  						break
    69  					}
    70  				}
    71  				runtime.Gosched()
    72  			}
    73  		})
    74  	}
    75  	wg.Wait()
    76  
    77  	tracebackOK = true
    78  }
    79  

View as plain text