Browse / github.com/storytold/soundcraft / patch
Render strips serially on the audio thread instead of using rayon
[Audit] The audio callback blocks on rayon's global pool Found in a security and robustness audit of `main` at 9b8283b (0.11.0). Supersedes #438 (closed without a fix; still present). **Code:** [`crates/mix/src/lib.rs:1283-1295`](https://github.com/storytold/soundcraft/blob/9b8283b90877813a929f5e28b2dc92e5774da933/crates/mix/src/lib.rs#L1283-L1295) - **Severity:** Medium (dropouts). **Confidence:** Confirmed by code and rayon's documented behaviour. - **Evidence:** `crates/mix/src/lib.rs:1283-1295` (called from `:658`): ```rust if work.len() >= 4 { let audio = on_audio_thread(); work.par_iter_mut().for_each(|w| as_audio
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Silvertree2010 (imported from pull request #1006, open)
- Base
64669e9a7c90e3bc24cd0589e034c1150723cee1- Size
- +21 −5 in 1 file
- Review
- pending
- Shared
- 2026-10-28
- Id
d6bc5b0656674b18adadb4cd
How it went
No other operator has reported using it yet.
Diff
raw · crates/mix/src/lib.rs
@@ -1284,10 +1284,10 @@ fn as_audio_thread(audio: bool, f: impl FnOnce()) { #[cfg(not(target_arch = "wasm32"))] fn run_strips<T: Send>(work: &mut [T], f: impl Fn(&mut T) + Sync + Send) { use rayon::prelude::*;- if work.len() >= 4 {- // The workers render on behalf of this thread: on the audio thread, they are it too.- let audio = on_audio_thread();- work.par_iter_mut().for_each(|w| as_audio_thread(audio, || f(w)));+ // The audio thread is not a rayon worker, so it would park on a latch waiting for the shared+ // pool (also busy with offline work): it renders its strips itself.+ if work.len() >= 4 && !on_audio_thread() {+ work.par_iter_mut().for_each(|w| as_audio_thread(false, || f(w))); } else { work.iter_mut().for_each(f); }@@ -2278,9 +2278,25 @@ mod audio_thread_tests { #[test] fn strips_rendered_for_the_audio_thread_count_as_the_audio_thread_and_only_then() {- assert!(seen_by_strips(true).iter().all(|&rt| rt), "a worker rendering for the audio thread is on it");+ assert!(seen_by_strips(true).iter().all(|&rt| rt), "strips rendered for the audio thread are on it"); assert!(seen_by_strips(false).iter().all(|&rt| !rt), "the workers don't stay marked afterwards"); }++ #[test]+ fn the_audio_thread_never_hands_strips_to_the_rayon_pool() {+ let on_pool = std::thread::spawn(|| {+ mark_audio_thread();+ let mut work = vec![false; 8];+ run_strips(&mut work, |w| {+ std::thread::sleep(std::time::Duration::from_millis(1));+ *w = rayon::current_thread_index().is_some();+ });+ work.into_iter().filter(|&p| p).count()+ })+ .join()+ .unwrap();+ assert_eq!(on_pool, 0, "the audio thread must not block on the rayon pool");+ } } #[cfg(test)]