• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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