Two Rust crates each bundle their own libcrypto (OpenSSL + BoringSSL) and fight over the same symbols — what's the right way to deal with this?

2026-08-30

Stack Overflow: View Question

Tags: rust, cryptography, linker, rusqlite, advice

Score: 0 | Views: 110

The asker has a Rust desktop app that pulls in two dependencies that each statically bundle their own crypto library: rusqlite with bundled-sqlcipher (built against OpenSSL) and livekit via webrtc-sys (bundling BoringSSL). Because BoringSSL is an API-compatible fork of OpenSSL, both objects export overlapping symbol names — SSL_CTX_new, EVP_*, RSA_*, etc. — with subtly different ABIs and struct layouts. At link time you either get "multiple definition" errors or, worse, one wins and the other crate silently calls into the wrong implementation, corrupting state or crashing on first use.

Why it's hard: This isn't a Rust-level problem — it's a C symbol collision that Cargo can't see. Rust's crate namespacing doesn't help once you cross the FFI boundary. Both static archives dump their symbols into the final binary's global namespace, and ELF/Mach-O/PE all resolve by name. The ABIs look identical but aren't (BoringSSL removed things, changed struct layouts, and its SSL_CTX is smaller than OpenSSL's). A pointer allocated by one and freed by the other is a heap corruption waiting to happen.

Approaches, roughly in order of pragmatism:

Gotchas: even after you "fix" the link, watch for TLS init clashes (both libraries may install signal handlers or global engines), FIPS-mode assumptions, and the fact that OpenSSL and BoringSSL disagree on error-queue semantics. On macOS the two-level namespace hides some of this until you ship; on Linux with default flat namespace, expect louder failures. And test in release mode — LTO can reshuffle which duplicate "wins."

The challenge: Cargo's dependency isolation stops at the FFI boundary, and once two vendored C libraries with overlapping symbol namespaces land in the same binary, the fix requires linker-level surgery that Rust tooling wasn't designed to express.

All newsletters