1// Copyright 2017 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//go:build !plan9 && !windows
6// +build !plan9,!windows
7
8// Test handling of Go-allocated signal stacks when calling from
9// C-created threads with and without signal stacks. (See issue
10// #22930.)
11
12package main
13
14/*
15#include <pthread.h>
16#include <signal.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <sys/mman.h>
20
21#ifdef _AIX
22// On AIX, SIGSTKSZ is too small to handle Go sighandler.
23#define CSIGSTKSZ 0x4000
24#else
25#define CSIGSTKSZ SIGSTKSZ
26#endif
27
28extern void SigStackCallback();
29
30static void* WithSigStack(void* arg __attribute__((unused))) {
31	// Set up an alternate system stack.
32	void* base = mmap(0, CSIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
33	if (base == MAP_FAILED) {
34		perror("mmap failed");
35		abort();
36	}
37	stack_t st = {}, ost = {};
38	st.ss_sp = (char*)base;
39	st.ss_flags = 0;
40	st.ss_size = CSIGSTKSZ;
41	if (sigaltstack(&st, &ost) < 0) {
42		perror("sigaltstack failed");
43		abort();
44	}
45
46	// Call Go.
47	SigStackCallback();
48
49	// Disable signal stack and protect it so we can detect reuse.
50	if (ost.ss_flags & SS_DISABLE) {
51		// Darwin libsystem has a bug where it checks ss_size
52		// even if SS_DISABLE is set. (The kernel gets it right.)
53		ost.ss_size = CSIGSTKSZ;
54	}
55	if (sigaltstack(&ost, NULL) < 0) {
56		perror("sigaltstack restore failed");
57		abort();
58	}
59	mprotect(base, CSIGSTKSZ, PROT_NONE);
60	return NULL;
61}
62
63static void* WithoutSigStack(void* arg __attribute__((unused))) {
64	SigStackCallback();
65	return NULL;
66}
67
68static void DoThread(int sigstack) {
69	pthread_t tid;
70	if (sigstack) {
71		pthread_create(&tid, NULL, WithSigStack, NULL);
72	} else {
73		pthread_create(&tid, NULL, WithoutSigStack, NULL);
74	}
75	pthread_join(tid, NULL);
76}
77*/
78import "C"
79
80func init() {
81	register("SigStack", SigStack)
82}
83
84func SigStack() {
85	C.DoThread(0)
86	C.DoThread(1)
87	C.DoThread(0)
88	C.DoThread(1)
89	println("OK")
90}
91
92var BadPtr *int
93
94//export SigStackCallback
95func SigStackCallback() {
96	// Cause the Go signal handler to run.
97	defer func() { recover() }()
98	*BadPtr = 42
99}
100