1 // Copyright 2021 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 #include <pthread.h> 9 #include <signal.h> 10 #include <stdint.h> 11 12 #include <sanitizer/msan_interface.h> 13 14 // cgoTracebackArg is the type of the argument passed to msanGoTraceback. 15 struct cgoTracebackArg { 16 uintptr_t context; 17 uintptr_t sigContext; 18 uintptr_t* buf; 19 uintptr_t max; 20 }; 21 22 // msanGoTraceback is registered as the cgo traceback function. 23 // This will be called when a signal occurs. 24 void msanGoTraceback(void* parg) { 25 struct cgoTracebackArg* arg = (struct cgoTracebackArg*)(parg); 26 arg->buf[0] = 0; 27 } 28 29 // msanGoWait will be called with all registers undefined as far as 30 // msan is concerned. It just waits for a signal. 31 // Because the registers are msan-undefined, the signal handler will 32 // be invoked with all registers msan-undefined. 33 __attribute__((noinline)) 34 void msanGoWait(unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, unsigned long a6) { 35 sigset_t mask; 36 37 sigemptyset(&mask); 38 sigsuspend(&mask); 39 } 40 41 // msanGoSignalThread is the thread ID of the msanGoLoop thread. 42 static pthread_t msanGoSignalThread; 43 44 // msanGoSignalThreadSet is used to record that msanGoSignalThread 45 // has been initialized. This is accessed atomically. 46 static int32_t msanGoSignalThreadSet; 47 48 // uninit is explicitly poisoned, so that we can make all registers 49 // undefined by calling msanGoWait. 50 static unsigned long uninit; 51 52 // msanGoLoop loops calling msanGoWait, with the arguments passed 53 // such that msan thinks that they are undefined. msan permits 54 // undefined values to be used as long as they are not used to 55 // for conditionals or for memory access. 56 void msanGoLoop() { 57 int i; 58 59 msanGoSignalThread = pthread_self(); 60 __atomic_store_n(&msanGoSignalThreadSet, 1, __ATOMIC_SEQ_CST); 61 62 // Force uninit to be undefined for msan. 63 __msan_poison(&uninit, sizeof uninit); 64 for (i = 0; i < 100; i++) { 65 msanGoWait(uninit, uninit, uninit, uninit, uninit, uninit); 66 } 67 } 68 69 // msanGoReady returns whether msanGoSignalThread is set. 70 int msanGoReady() { 71 return __atomic_load_n(&msanGoSignalThreadSet, __ATOMIC_SEQ_CST) != 0; 72 } 73 74 // msanGoSendSignal sends a signal to the msanGoLoop thread. 75 void msanGoSendSignal() { 76 pthread_kill(msanGoSignalThread, SIGWINCH); 77 } 78 */ 79 import "C" 80 81 import ( 82 "runtime" 83 "time" 84 ) 85 86 func main() { 87 runtime.SetCgoTraceback(0, C.msanGoTraceback, nil, nil) 88 89 c := make(chan bool) 90 go func() { 91 defer func() { c <- true }() 92 C.msanGoLoop() 93 }() 94 95 for C.msanGoReady() == 0 { 96 time.Sleep(time.Microsecond) 97 } 98 99 loop: 100 for { 101 select { 102 case <-c: 103 break loop 104 default: 105 C.msanGoSendSignal() 106 time.Sleep(time.Microsecond) 107 } 108 } 109 } 110