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 5package 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. 15struct 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. 24void 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)) 34void 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. 42static pthread_t msanGoSignalThread; 43 44// msanGoSignalThreadSet is used to record that msanGoSignalThread 45// has been initialized. This is accessed atomically. 46static int32_t msanGoSignalThreadSet; 47 48// uninit is explicitly poisoned, so that we can make all registers 49// undefined by calling msanGoWait. 50static 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. 56void 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. 70int msanGoReady() { 71 return __atomic_load_n(&msanGoSignalThreadSet, __ATOMIC_SEQ_CST) != 0; 72} 73 74// msanGoSendSignal sends a signal to the msanGoLoop thread. 75void msanGoSendSignal() { 76 pthread_kill(msanGoSignalThread, SIGWINCH); 77} 78*/ 79import "C" 80 81import ( 82 "runtime" 83 "time" 84) 85 86func 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 99loop: 100 for { 101 select { 102 case <-c: 103 break loop 104 default: 105 C.msanGoSendSignal() 106 time.Sleep(time.Microsecond) 107 } 108 } 109} 110