| // 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 |
| } |