forked from pact-foundation/pact-reference
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test: demonstrate issue with signal handling in golang with pact_ffi
- Loading branch information
Showing
21 changed files
with
4,465 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
SKIP_SIGNAL_HANDLERS?=false | ||
TEST_COUNT?=50 | ||
RACE=-race | ||
CGO_ENABLED=1 | ||
ifeq ($(CGO_ENABLED),0) | ||
SKIP_RACE=true | ||
endif | ||
ifeq ($(SKIP_RACE),true) | ||
RACE= | ||
endif | ||
# export PACT_PROVIDER_DIR?=./pacts_plugin_protobuf | ||
|
||
ifeq ($(PACT_PROVIDER),protobuf) | ||
export PACT_PROVIDER_DIR=./pacts_plugin_protobuf | ||
else ifeq ($(PACT_PROVIDER),csv) | ||
export PACT_PROVIDER_DIR=./pacts_plugin_csv | ||
else ifeq ($(PACT_PROVIDER),avro) | ||
export PACT_PROVIDER_DIR=./pacts_plugin_avro | ||
else ifeq ($(PACT_PROVIDER),message) | ||
export PACT_PROVIDER_DIR=./pacts_plugin_message | ||
else | ||
export PACT_PROVIDER_DIR=./pacts_http | ||
endif | ||
|
||
run: | ||
go run pact/go/native/native | ||
|
||
test: | ||
go test -v $(SKIP_RACE) -count $(TEST_COUNT) pact/go/native/native | ||
|
||
test_protobuf: | ||
make test PACT_PROVIDER=protobuf | ||
test_csv: | ||
make test PACT_PROVIDER=csv | ||
test_avro: | ||
make test PACT_PROVIDER=avro | ||
test_go: | ||
make test PACT_PROVIDER=go | ||
test_message: | ||
make test | ||
test_http: | ||
make test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module pact/go/native | ||
|
||
go 1.22.2 | ||
|
||
require ( | ||
github.com/ebitengine/purego v0.7.1 | ||
golang.org/x/sys v0.21.0 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
github.com/ebitengine/purego v0.7.1 h1:6/55d26lG3o9VCZX8lping+bZcmShseiqlh2bnUDiPA= | ||
github.com/ebitengine/purego v0.7.1/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= | ||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= | ||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Go Interop with Rust Issue | ||
|
||
This is an example which shows a Rust project which has been compiled as a shared library, and is called from multiple languages including Go. | ||
|
||
The rust project, may call out to external executables (called plugins) which can be written in any language. | ||
|
||
This is currently causing issues with occasional segfaults in Linux / MacOS. | ||
|
||
## Rust shared library | ||
|
||
The rust shared library is currently built for the following platforms. | ||
|
||
- x86_64-unknown-linux-gnu | ||
- aarch64-unknown-linux-gnu | ||
- x86_64-unknown-linux-musl | ||
- aarch64-unknown-linux-musl | ||
- x86_64-apple-darwin | ||
- aarch64-apple-darwin | ||
- x86_64-pc-windows-msvc | ||
- aarch64-pc-windows-msvc | ||
|
||
## Calling languages | ||
|
||
It is called from various languages, including but not limited to: | ||
|
||
- Golang (via cgo) | ||
- JS (via node-napi) | ||
- PHP (via FFI) | ||
- Python (via cffi) | ||
|
||
## Plugins, controlled by the rust shared library | ||
|
||
The shared library, may load plugins which are written in any language, and may call out to external executables which are written in any language. | ||
|
||
The following languages are currently being used as plugins: | ||
|
||
- Golang | ||
- Built with GoReleaser for the following platforms: | ||
- linux/amd64 | ||
- linux/arm64 | ||
- darwin/amd64 | ||
- darwin/arm64 | ||
- windows/amd64 | ||
- windows/arm64 | ||
- Rust | ||
- Built with cross / cargo | ||
- For linux, musl static builds are used to work on glibc & musl systems | ||
- x86_64-unknown-linux-musl | ||
- aarch64-unknown-linux-musl | ||
- x86_64-apple-darwin | ||
- aarch64-apple-darwin | ||
- x86_64-pc-windows-msvc | ||
- aarch64-pc-windows-msvc | ||
- Java | ||
- Requires user to have openjdk 17 installed | ||
|
||
## Issues | ||
|
||
### Issue 1 - Segfaults on Linux / MacOS | ||
|
||
``` | ||
signal 17 received but handler not on signal stack | ||
mp.gsignal stack [0x400006e000 0x4000076000], mp.g0 stack [0xffff4320e810 0xffff43a0e410], sp=0x40000e3608 | ||
fatal error: non-Go code set up signal handler without SA_ONSTACK flag | ||
``` | ||
|
||
Fixed by workaround in following PR | ||
|
||
- https://github.com/wailsapp/wails/pull/2152/files#diff-d4a0fa73df7b0ab971e550f95249e358b634836e925ace96f7400480916ac09e | ||
|
||
> Sets up a new signal handler in C that overrides the current one (in C) so that SA_ONSTACK is used. | ||
See golang docs for os/signal | ||
|
||
https://pkg.go.dev/os/signal#hdr-Go_programs_that_use_cgo_or_SWIG | ||
|
||
> If the non-Go code installs any signal handlers, it must use the SA_ONSTACK flag with sigaction. Failing to do so is likely to cause the program to crash if the signal is received. Go programs routinely run with a limited stack, and therefore set up an alternate signal stack. | ||
#### Additional Problems | ||
|
||
1. Does not fix Alpine linux | ||
2. Fix does not with CGO_ENABLED=0 using https://github.com/ebitengine/purego, as it requires C code to be injected. | ||
1. Probably fix needs to be applied to fakego in purego | ||
|
||
## Testing | ||
|
||
- Use of CGO or ebitengine/purego is controlled by `CGO_ENABLED=1` for `cgo` and `CGO_ENABLED=0` for `purego` | ||
- Fix can be removed by settings `SKIP_SIGNAL_HANDLERS=true` | ||
|
||
### Issue 2 - Windows plugin executables are not shutdown properly | ||
|
||
``` | ||
*** Test I/O incomplete 1m0s after exiting. | ||
exec: WaitDelay expired before I/O complete | ||
``` | ||
|
||
The windows executable is shutdown externally via taskkill or the task manager, will exit the plugin correctly and the test will pass. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
//go:build cgo | ||
// +build cgo | ||
|
||
// Package native contains the c bindings into the Pact Reference types. | ||
package main | ||
|
||
/* | ||
#cgo darwin,arm64 LDFLAGS: -L/tmp -L/usr/local/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi | ||
#cgo darwin,amd64 LDFLAGS: -L/tmp -L/usr/local/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi | ||
#cgo windows,amd64 LDFLAGS: -lpact_ffi | ||
#cgo linux,amd64 LDFLAGS: -L/tmp -L/opt/pact/lib -L/usr/local/lib -Wl,-rpath -Wl,/opt/pact/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi | ||
#cgo linux,arm64 LDFLAGS: -L/tmp -L/opt/pact/lib -L/usr/local/lib -Wl,-rpath -Wl,/opt/pact/lib -Wl,-rpath -Wl,/tmp -Wl,-rpath -Wl,/usr/local/lib -lpact_ffi | ||
#include "pact.h" | ||
*/ | ||
import "C" | ||
import ( | ||
"fmt" | ||
"os" | ||
) | ||
|
||
func plugin_provider() int { | ||
verifier := C.pactffi_verifier_new() | ||
// C.pactffi_log_to_stdout(0) | ||
C.pactffi_verifier_set_provider_info(verifier, C.CString("p1"), C.CString("http"), C.CString("localhost"), 8000, C.CString("/")) | ||
// C.pactffi_verifier_add_provider_transport(verifier, C.CString("http"), 8000, C.CString("/"), C.CString("http")) | ||
// C.pactffi_verifier_add_provider_transport(verifier, C.CString("protobuf"), 37757, C.CString("/"), C.CString("tcp")) | ||
|
||
C.pactffi_verifier_add_directory_source(verifier, C.CString(os.Getenv("PACT_PROVIDER_DIR"))) | ||
InstallSignalHandlers() | ||
defer C.pactffi_verifier_shutdown(verifier) | ||
result := C.pactffi_verifier_execute(verifier) | ||
if result != 0 { | ||
fmt.Printf("Result is not 0: %d", result) | ||
} else { | ||
fmt.Print("Result success") | ||
} | ||
return int(result) | ||
} |
Oops, something went wrong.