Skip to content

Segfault at process exit when zvec is statically linked (glog/protobuf destructor ordering) #206

@thedonmon

Description

@thedonmon

Description

When zvec is statically linked into a host application (in our case via a Rust/Elixir NIF bridge), the process segfaults during shutdown. All zvec operations work correctly during the process lifetime — the crash only occurs at exit.

Root Cause

The segfault is caused by C++ static destructor ordering. zvec statically links glog, protobuf, gflags, and RocksDB, all of which register atexit handlers for global cleanup. At process exit, these destructors run in reverse registration order, but some depend on globals that were already destroyed by earlier destructors (e.g., glog tries to flush to a logger after protobuf has cleaned up).

Steps to Reproduce

Statically link zvec (with all dependencies) into any application, perform some operations, then exit. The process will segfault with exit code 139 (SIGSEGV).

Impact

Low — this is cosmetic. All operations work correctly. The crash only happens at process shutdown. In long-running applications (servers, daemons), this is never visible. It primarily affects test runners that start and stop the process.

Suggested Fixes

  • Provide an explicit zvec::Shutdown() function that users can call before exit to clean up glog/protobuf/gflags in the correct order
  • Or use __attribute__((destructor)) with explicit priority ordering for cleanup functions
  • Or guard the glog/protobuf shutdown code against double-free / use-after-free of globals

Environment

  • macOS ARM64 (Apple Silicon) + Linux x86_64
  • zvec built with -DBUILD_SHARED_LIBS=OFF (static linking)
  • Host: Elixir/Rust NIF via Rustler + cxx bridge
  • Reproducible with any host that statically links zvec and then exits

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions