| // Copyright 2017 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| //go:build !plan9 && !windows | |
| // +build !plan9,!windows | |
| // Test handling of Go-allocated signal stacks when calling from | |
| // C-created threads with and without signal stacks. (See issue | |
| // #22930.) | |
| package main | |
| /* | |
| #include <pthread.h> | |
| #include <signal.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/mman.h> | |
| #ifdef _AIX | |
| // On AIX, SIGSTKSZ is too small to handle Go sighandler. | |
| #define CSIGSTKSZ 0x4000 | |
| #else | |
| #define CSIGSTKSZ SIGSTKSZ | |
| #endif | |
| extern void SigStackCallback(); | |
| static void* WithSigStack(void* arg __attribute__((unused))) { | |
| // Set up an alternate system stack. | |
| void* base = mmap(0, CSIGSTKSZ, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); | |
| if (base == MAP_FAILED) { | |
| perror("mmap failed"); | |
| abort(); | |
| } | |
| stack_t st = {}, ost = {}; | |
| st.ss_sp = (char*)base; | |
| st.ss_flags = 0; | |
| st.ss_size = CSIGSTKSZ; | |
| if (sigaltstack(&st, &ost) < 0) { | |
| perror("sigaltstack failed"); | |
| abort(); | |
| } | |
| // Call Go. | |
| SigStackCallback(); | |
| // Disable signal stack and protect it so we can detect reuse. | |
| if (ost.ss_flags & SS_DISABLE) { | |
| // Darwin libsystem has a bug where it checks ss_size | |
| // even if SS_DISABLE is set. (The kernel gets it right.) | |
| ost.ss_size = CSIGSTKSZ; | |
| } | |
| if (sigaltstack(&ost, NULL) < 0) { | |
| perror("sigaltstack restore failed"); | |
| abort(); | |
| } | |
| mprotect(base, CSIGSTKSZ, PROT_NONE); | |
| return NULL; | |
| } | |
| static void* WithoutSigStack(void* arg __attribute__((unused))) { | |
| SigStackCallback(); | |
| return NULL; | |
| } | |
| static void DoThread(int sigstack) { | |
| pthread_t tid; | |
| if (sigstack) { | |
| pthread_create(&tid, NULL, WithSigStack, NULL); | |
| } else { | |
| pthread_create(&tid, NULL, WithoutSigStack, NULL); | |
| } | |
| pthread_join(tid, NULL); | |
| } | |
| */ | |
| import "C" | |
| func init() { | |
| register("SigStack", SigStack) | |
| } | |
| func SigStack() { | |
| C.DoThread(0) | |
| C.DoThread(1) | |
| C.DoThread(0) | |
| C.DoThread(1) | |
| println("OK") | |
| } | |
| var BadPtr *int | |
| //export SigStackCallback | |
| func SigStackCallback() { | |
| // Cause the Go signal handler to run. | |
| defer func() { recover() }() | |
| *BadPtr = 42 | |
| } | |