From 79bf025862f91a7d1ec756e88a8903bac9de7269 Mon Sep 17 00:00:00 2001 From: Robin Gareus Date: Sat, 8 May 2021 23:29:49 +0200 Subject: [PATCH] Fix export race condition (and crash) Previously the freewheel export thread directly called Session::butler_transport_work(). The butler thread may concurrently call the same function. This can lead double free or memory corruption (see below) Now export thread summons the butler and does nothing until it completed its work. ``` Export Thread: 3 XMLNode::~XMLNode 4 ARDOUR::AutomationList::snapshot_history 5 ARDOUR::AutomationList::start_write_pass 6 ARDOUR::Automatable::non_realtime_locate 7 ARDOUR::Route::non_realtime_locate 8 ARDOUR::Session::non_realtime_locate 9 ARDOUR::Session::butler_transport_work 10 ARDOUR::Session::process_export_fw Butler thread: 7 XMLNode::~XMLNode 8 ARDOUR::AutomationList::snapshot_history 9 ARDOUR::AutomationList::start_write_pass 10 ARDOUR::Automatable::non_realtime_locate 11 ARDOUR::Route::non_realtime_locate 12 ARDOUR::Session::non_realtime_locate 13 ARDOUR::Session::butler_transport_work 14 ARDOUR::Butler::thread_work 15 ARDOUR::Butler::_thread_work ``` --- libs/ardour/session_export.cc | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 8870d6e2ac..c61255a189 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -307,9 +307,8 @@ Session::process_export_fw (pframes_t nframes) TFSM_SPEED (1.0, false); TFSM_ROLL (); - butler_transport_work (true); - g_atomic_int_set (&_butler->should_do_transport_work, 0); - butler_completed_transport_work (); + _butler->schedule_transport_work (); + /* Session::process_with_events () sets _remaining_latency_preroll = 0 * when being called with _transport_fsm->transport_speed() == 0. * @@ -323,6 +322,16 @@ Session::process_export_fw (pframes_t nframes) return; } + /* wait for butler to complete schedule_transport_work(), + * compare to Session::process */ + if (non_realtime_work_pending ()) { + if (_butler->transport_work_requested ()) { + /* butler is still processing */ + return; + } + butler_completed_transport_work (); + } + if (_remaining_latency_preroll > 0) { samplepos_t remain = std::min ((samplepos_t)nframes, _remaining_latency_preroll);