13
0

Fix signal emission order ambiguity (record regionview)

A rec-region is added to the streamview just like any other region
(::add_region_view_internal). This subscribes to region->DropReferences.

When the DropReferences is handled first by StreamView::remove_region_view
the corresponding RegionView is destroyed.

This can happen even while recording is still active, eg. when locating
(which stops the current recording).
MidiStreamView::setup_rec_box() is called and crashes in
`dynamic_cast<MidiRegionView*> (rec_regions.back().second);`
due to a use after free.

Strictly speaking this is a logic error in how ::setup_rec_box()
determines if to add or remove the rec-box. But due to the
asynchronous nature of signal emission and transport-state changes
the best solution is to destroy the rec-region at the same
when the RegionView is destroyed.

To reproduce:
 * create a session with a MIDI track
 * disconnect the input (empty MIDI regions are removed)
 * Preferences > Transport > *enable* latched-record-enable
 * use the Dummy backend's MIDI generator
 * connect Hardware > MIDI > MMC -> Ardour misc > MMC in
   OR use JACK-transport to locate while recording.
This commit is contained in:
Robin Gareus 2023-06-04 21:42:02 +02:00
parent ad5d355fb5
commit 464df06419
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -193,6 +193,23 @@ StreamView::remove_region_view (std::weak_ptr<Region> weak_r)
return;
}
bool clear_rec_rects = false;
for (list<pair<std::shared_ptr<Region>,RegionView*> >::iterator i = rec_regions.begin(); i != rec_regions.end();) {
if (i->first == r) {
i = rec_regions.erase (i);
clear_rec_rects = true;
} else {
++i;
}
}
if (clear_rec_rects) {
for (auto const& i : rec_rects) {
delete i.rectangle;
}
rec_rects.clear();
}
for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
if (((*i)->region()) == r) {
RegionView* rv = *i;
@ -477,7 +494,8 @@ StreamView::cleanup_rec_box ()
rec_active = false;
/* remove temp regions */
for (auto const& i : rec_regions) {
auto rr (rec_regions);
for (auto const& i : rr) {
i.first->drop_references ();
}