mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-28 12:36:47 -06:00
vst3-host ran each module's entry (bundleEntry / InitDll / ModuleEntry) when it loaded a .vst3 and cached the module for the life of the process, but never ran the matching exit or released the cached factory. At exit() the module's static destructors then ran on a module that was never shut down. Steinberg's HALion Sonic segfaults there, so every process that had scanned VST3 plugins crashed on exit: the app on quit, soundcraft-cli, and the engine, mix and vst3-host unit tests. At process exit each module now has its factory released and its exit run, newest first, on the thread that ran its entry: Native Instruments' Massive X crashes in bundleExit on any other thread. Loads asked for off the main thread go to a long-lived module thread, which also runs their exits. Modules with a live instance or a leaked editor view are left alone, later loads are refused, and plugin code stays mapped. The exit handler is registered with atexit after each new module, so it runs ahead of that module's static destructors; it uses OS thread ids because std::thread::current() panics in exit handlers. A module whose entry ran but that then fails to load now gets its exit too. The fixture plugin now checks the module lifecycle and aborts the process when it is broken. Three harness = false tests cover the exit after use, a live instance at exit, and a load from a short-lived thread. Fixes #16 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
18 lines
799 B
Rust
18 lines
799 B
Rust
//! A module first loaded from a short-lived thread is entered and, at process exit, exited on
|
|
//! one thread that outlives it (`harness = false`, see `module_exit.rs`): the asking thread is
|
|
//! gone by then, and modules tie state to the thread of their entry (Massive X crashed in a
|
|
//! module exit run on another thread). The fixture aborts the process if the threads differ.
|
|
|
|
mod common;
|
|
|
|
fn main() {
|
|
std::thread::spawn(|| {
|
|
let dir = common::fixture_dir();
|
|
let gain = soundcraft_vst3_host::scan_paths(&[dir.to_path_buf()]).into_iter().find(|d| d.name == "Fixture Gain").expect("fixture").id;
|
|
drop(soundcraft_vst3_host::instantiate_plugin(&gain).expect("instantiate"));
|
|
})
|
|
.join()
|
|
.expect("worker thread");
|
|
println!("module_exit_worker_thread: ok");
|
|
}
|