Segmentation faults when adding printing functions in tsan for Golang

14 views
Skip to first unread message

Shi Zheng

unread,
Dec 16, 2024, 9:03:56 AM12/16/24
to thread-sanitizer
Hi tsan developers,

We are trying to modify tsan for Golang to print some traces for multi-threaded programs. To be more specific, we want to print the channel-related events, such as send, recv etc. 

To do this, we have done the following modifications. For example, in order to print the channel send events, 

1. we add a function racechansend(addr unsafe.Pointer, pc uintptr), which takes the channel address addr and program counter pc as inputs, in golang/src/runtime/race0.go and golang/src/runtime/race.go. In race0.go, this is an empty function that only throws race exceptions (because this file only contains functions when race detector is not enabled for Go). In race.go, it calls racecall(&__tsan_chan_send, getg().racectx, uintptr(addr), pc, 0)

2. we add a function void __tsan_chan_send(ThreadState *thr, uptr addr, uptr pc) in tsan_go.cpp under llvm/compiler-rt/lib/tsan/go/ which simply does some printing.

3. we call this racechansend function in golang/src/runtime/chan.go

This works fine, but we have encountered some segmentation faults when we try to print out the call stack of some memory read/write instructions using function void PrintCurrentStack(ThreadState *thr, uptr pc) from tsan_rtl_report.cpp

After some debugging, we belive the problem is caused by the go_runtime_cb in tsan_go.cpp, which calls back into Golang code. That is, PrintCurrentStack will call go_runtime_cb and the problem is that somehow the current thread context g is set to be null, and when trying to access the field g.m, it causes segmentation faults (the assembly instruction MOVQ g_m(R14), R13 from function runtime·racecallbackthunk in golang/src/runtime/race_amd64.s). 

We wonder if you have any ideas why this is happening, and how should we fix this problem? Thanks!

Dmitry Vyukov

unread,
Dec 16, 2024, 9:07:40 AM12/16/24
to Shi Zheng, thread-sanitizer, golang-dev

I would check that g is not nil _before_ all race callbacks on the Go side.
If you catch such a case, it should be easier to debug on the Go side, if call throw, it should also print the current stack.
Reply all
Reply to author
Forward
0 new messages