Skip to content

--allow-multiple-definition RUSTFLAGS breaks inventory crate engine registration, causing integration test failures #438

@uran0sH

Description

@uran0sH

Integration tests fail when running make test:all. I add RUSTFLAGS="-C link-arg=-Wl,--allow-multiple-definition" to make/test.mk to work around duplicate symbol errors from libkrun.a(refer #437), but this flag silently breaks the inventory crate's compile-time registration mechanism.

Root Cause

Why --allow-multiple-definition is needed

libkrun.a is built from Rust source via cargo rustc --crate-type staticlib (see src/deps/libkrun-sys/build.rs). It embeds its own copy of the Rust standard library, compiled with a different toolchain version. When the test binary links against both the current libstd and the one inside libkrun.a, the linker reports hundreds of duplicate symbols:

duplicate symbol: std::sys::args::unix::imp::ARGV_INIT_ARRAY
duplicate symbol: std::panicking::EMPTY_PANIC
...

Without --allow-multiple-definition, linking fails entirely.

Why --allow-multiple-definition breaks inventory

The inventory crate (v0.3) works by placing submit! entries into a custom ELF linker section. The linker merges all such sections across compilation units and exposes section bounds via __start_<section> / __stop_<section> symbols. inventory::iter! uses these symbols to traverse collected entries at runtime.

When --allow-multiple-definition is active, the linker silently picks one definition when it encounters duplicates. Since libkrun.a also contains Rust stdlib artifacts (which may carry section data that interferes with inventory's markers), the __start_section / __stop_section bounds end up pointing to an empty range. As a result, inventory::iter::<EngineFactoryRegistration>() returns an empty iterator.

Failure chain

make test:all
→ test:integration:rust
→ cargo test -p boxlite --features krun,gvproxy --test '*'
→ links libkrun.a (krun feature enabled)
→ --allow-multiple-definition suppresses duplicate symbol errors
→ inventory section markers resolve to empty range
→ inventory::iter returns nothing
→ "Engine Libkrun is not registered. Available engines: []"
→ shim process fails to start → all integration tests fail

Affected tests (11 total)

  • boxlite::detach::detached_box_recoverable_after_restart
  • boxlite::execution_shutdown::test_concurrent_exec_workdir
  • boxlite::jailer::jailer_creates_isolated_mount_namespace
  • boxlite::jailer::jailer_enabled_box_starts_and_executes
  • boxlite::pid_file::is_same_process_validates_boxlite_shim
  • boxlite::pid_file::pid_file_contains_correct_pid
  • boxlite::recovery::recovery_with_live_process
  • boxlite::zygote_integration::test_zygote_concurrent_mixed_durations
  • boxlite::zygote_integration::test_zygote_concurrent_stdin_pipes
  • boxlite::zygote_integration::test_zygote_high_concurrency_16
  • boxlite::zygote_integration::test_zygote_repeated_bursts

Relevant files

  • make/test.mk — where RUSTFLAGS is set
  • src/boxlite/src/vmm/registry.rsinventory::collect! and inventory::iter! usage
  • src/boxlite/src/vmm/krun/factory.rsinventory::submit! for Libkrun engine
  • src/boxlite/Cargo.toml:69inventory = "0.3" dependency
  • src/deps/libkrun-sys/build.rs — builds libkrun.a from Rust source

Possible solutions

Approach Description Trade-off
Replace inventory with direct match Dispatch on VmmKind via match arms with #[cfg(feature = "krun")] guards. Remove inventory dependency entirely. Simplest and most robust. No linker tricks needed. 3 files changed, 1 dependency removed.
Targeted duplicate symbol handling Use linker version scripts or --undefined-version to allow only std::* duplicates while preserving inventory section markers. More precise but fragile; hard to guarantee inventory symbols are unaffected.
Patch inventory crate Mark section marker symbols with __attribute__((used)) to prevent the linker from discarding them. Requires forking inventory; may not fully resolve the conflict.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions