Source file src/runtime/testdata/testprogcgo/sigstack.go
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 12 package 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 28 extern void SigStackCallback(); 29 30 static 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 63 static void* WithoutSigStack(void* arg __attribute__((unused))) { 64 SigStackCallback(); 65 return NULL; 66 } 67 68 static 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 */ 78 import "C" 79 80 func init() { 81 register("SigStack", SigStack) 82 } 83 84 func SigStack() { 85 C.DoThread(0) 86 C.DoThread(1) 87 C.DoThread(0) 88 C.DoThread(1) 89 println("OK") 90 } 91 92 var BadPtr *int 93 94 //export SigStackCallback 95 func SigStackCallback() { 96 // Cause the Go signal handler to run. 97 defer func() { recover() }() 98 *BadPtr = 42 99 } 100