bash build.sh --test SIGSEGVs in static init: duplicate protobuf symbols inside libonnxruntime.a (internal/ingestion/component)
Summary
Following the Go verification path in AGENTS.md — bash build.sh --test ./internal/ingestion/component/... — the test binary segfaults during static initialisation, before any Go code runs. bash build.sh itself succeeds, so this is not a link failure; the crash happens when the binary starts.
That makes internal/ingestion/component untestable on the documented path for anyone building from source.
Reproduce
On a clean checkout with the CGO toolchain and native deps present (gcc 13.3.0, clang 18.1.3, lld 18.1.3, cmake >= 4.0, plus office_oxide, pdfium-static, pdf_oxide, onnxruntime 1.29.0):
bash build.sh # exit 0, builds ragflow_server + ragflow-cli
bash build.sh --test ./internal/ingestion/component/ # exit 1, signal: segmentation fault (core dumped)The test run produces no output at all — not even the first === RUN line. GOTRACEBACK=all does not help, because Go's main is never reached.
Backtrace
gdb 15.1, run directly on the compiled test binary:
Program received signal SIGSEGV, Segmentation fault.
#0 0x000000000586ed14 in __cxa_guard_release ()
#1 0x000000000586ed0a in __cxa_guard_acquire ()
#2 0x000000000762cdf0 in google::protobuf::internal::InitProtobufDefaultsSlow() ()
#3 0x00007fffffffe070 in ?? ()
#4 0x00007ffff782a304 in call_init (env=<optimized out>, argv=0x0, argc=3) at ../csu/libc-start.c:145
#5 __libc_start_main_impl (main=0x0, argc=3, ...)Frame #4 is call_init — this is ELF static initialisation. The crash is inside a protobuf function-local static guarded by __cxa_guard_acquire, before main.
Likely cause: duplicate protobuf symbols inside libonnxruntime.a
The objcopy step in build_cpp() renames the tokenizer's bundled re2 symbols into a private prefix, and that fix is working — the tokenizer archive has 1034 ragtokre2_-prefixed symbols after the rename.
But the filter only matches the re2 namespace:
awk '$2 ~ /^[TDBRWtdbrwiIVv]$/ && $3 ~ /^_ZN3re2|_ZNK3re2|_ZTVN3re2|_ZTIN3re2|_ZTSN3re2/ ...'protobuf is not covered. Measurements on the static archive (onnxruntime-linux-x64-static_lib-1.29.0-glibc2_28/lib/libonnxruntime.a):
| Measurement | Value |
|---|---|
| archive members | 650 |
distinct members carrying _ZN6google8protobuf |
34 |
total _ZN6google8protobuf symbols |
1625 |
definitions of google::protobuf::internal::InitProtobufDefaultsSlow |
2 |
Both definitions live in the same member, generated_message_util.cc.o. Two definitions of one symbol in a single object is exactly the condition that makes __cxa_guard_acquire operate on the wrong address at load time.
The tokenizer archive contains 0 protobuf symbols, so this is not a tokenizer/onnxruntime clash of the same kind as re2 — it is duplication within onnxruntime's own archive.
Why this looks like a packaging question, not a build-script one
build.sh already links working ragflow_server and ragflow-cli from the same CGO_LDFLAGS, and those binaries start fine. What differs for a go test binary is that the whole internal/ingestion/component package is linked into one test executable, pulling in more of the archive.
So the question is whether libonnxruntime.a 1.29.0 is expected to carry duplicate protobuf symbols, and if not, which copy should be dropped at packaging time.
Impact
internal/ingestion/componentcannot be tested via the documented command- CI is unaffected (it does not run this path with these libs), so this is easy to miss
- Anyone validating a change locally in that package hits it immediately
Environment
| OS | Ubuntu 24.04.4 (WSL2) |
| Go | 1.27.0 |
| gcc / clang / lld | 13.3.0 / 18.1.3 / 18.1.3 |
| cmake | 4.0.3 |
| onnxruntime | 1.29.0 static (DeepDocORTVersion=1.29.0) |
| base commit | 313ca90 |
Happy to test a fix or an alternative onnxruntime packaging if that helps.
Source: infiniflow/ragflow