100 lines
2.1 KiB
Go
100 lines
2.1 KiB
Go
|
// 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
|
||
|
}
|