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