SIGSEGV in `yrx_compiler_build` from Go bindings — regression in 1.15.0
## SIGSEGV in `yrx_compiler_build` from Go bindings — regression in 1.15.0
### Summary
Calling `Compiler.Build()` from the Go bindings consistently crashes with `SIGSEGV` (sigcode 2 / `SEGV_ACCERR`) inside the cgo call to `yrx_compiler_build`. The crash is deterministic, happens at the same PC across runs, and reproduces with a small ruleset (50k lines / ~few hundred rules). I bisected and the regression appeared in **v1.15.0**:
| version | result |
|---|---|
| 1.13.0 | works |
| 1.14.0 | works |
| **1.15.0** | **crashes** |
| 1.16.0 | (not retested, but expected to crash) |
| 1.17.0 | crashes |
Wasmtime version is unchanged between 1.14.0 and 1.15.0 (both 40.0.4), so it's not a wasmtime bump. My best guess is the "Add full support for WASM" change in 1.15.0 affected the compile path.
### Crash signature
```
SIGSEGV: segmentation violation
PC=0xe6fd14 m=11 sigcode=2 addr=0x7f96a3cccde0
signal arrived during cgo execution
goroutine 1 gp=0x31bc5bf581e0 m=11 mp=0x31bc5c172008 [syscall]:
runtime.cgocall(0x7600d0, 0x31bc5bf7d6d8)
/usr/local/go/src/runtime/cgocall.go:167 +0x4b
github.com/VirusTotal/yara-x/go._Cfunc_yrx_compiler_build(0x7f96a3f0e080)
_cgo_gotypes.go:508 +0x45
github.com/VirusTotal/yara-x/go.(*Compiler).Build.func1(...)
/go/pkg/mod/github.com/!virus!total/yara-x/go@v1.17.0/compiler.go:632
github.com/VirusTotal/yara-x/go.(*Compiler).Build(0x31bc5c05c240)
/go/pkg/mod/github.com/!virus!total/yara-x/go@v1.17.0/compiler.go:632 +0x48
main.main()
/build/main.go:98 +0xb2a
...
rsp 0x7f96a3cccdd0
rip 0xe6fd14
```
Crash hits after `AddSource` and `Warnings()` complete successfully. The fault address is exactly **16 bytes above rsp** — i.e. the first stack-local access after a large `sub rsp, N` on function entry — and `sigcode=2` (`SEGV_ACCERR`) on a page just past the stack base is the classic stack-guard-page hit. This points to a function in the compile path with a stack frame larger than the cgo-call stack the Go runtime provides for the M's g0 (which is fairly small on Linux).
The crash signature is identical (same PC, same offset, sigcode=2) whether the input is a 550k-line ruleset or a 50k-line one — so it's a fixed-size frame on the build path, not depth-dependent recursion.
### Reproducer
- Build environment: static musl binary on Alpine, Go cgo, yara-x C API linked statically.
- Triggering call: `Compiler.Build()` after a successful `AddSource` of a non-trivial ruleset.
- Build patches applied (none of which should be related, but for completeness):
- Remove `cdylib` from `capi/Cargo.toml` (keep only `staticlib`)
- `config.signals_based_traps(false)` added in `lib/src/wasm/mod.rs` (avoids wasmtime signal handler conflict with Go at scan time — not load-bearing for this crash)
- `RUSTFLAGS="-C target-feature=-crt-static"` so the .a doesn't bundle musl libc
Build command:
```
cargo build -p yara-x-capi --release \
--target x86_64-unknown-linux-musl \
--features=rules-profiling
```
Go link:
```
go build -ldflags "-extldflags '-static -llzma -Wl,-z,muldefs' -w -s" \
-tags static_link -o goodwarescanner-linux .
```
Happy to share a minimal Dockerfile and a Go reproducer if helpful.
### Workarounds considered
- Bumping the linker's ELF stack size (`-Wl,-z,stack-size=...`) — only affects the main thread, not Go-created Ms.
- Running `yrx_compiler_build` on a manually-created pthread with a larger stack via a C shim — should work but invasive.
- Wrapping internal recursive paths in `stacker::maybe_grow` in the Rust source.
For now I'm pinned to 1.14.0.
### Versions
- yara-x: 1.15.0+ (broken), 1.14.0 (works)
- yara-x/go bindings: same versions as above
- Go: as bundled in `golang:alpine` (cgo enabled)
- Rust: `rust:slim` (latest at time of build)
- Target: `x86_64-unknown-linux-musl`
10 条评论