Mixer: Fix crash when closing project containing certain configurations of modules.

This commit is contained in:
Jonathan Moore Liles 2020-12-02 20:13:44 -08:00
parent 97d12322f5
commit 0106604073
10 changed files with 114 additions and 53 deletions

View File

@ -174,6 +174,8 @@ Chain::~Chain ( )
_deleting = true; _deleting = true;
/* FIXME: client may already be dead during teardown if group is destroyed first. */
if ( client() )
client()->lock(); client()->lock();
for ( unsigned int i = scratch_port.size(); i--; ) for ( unsigned int i = scratch_port.size(); i--; )
@ -182,8 +184,11 @@ Chain::~Chain ( )
/* if we leave this up to FLTK, it will happen after we've /* if we leave this up to FLTK, it will happen after we've
already destroyed the client */ already destroyed the client */
modules_pack->clear(); modules_pack->clear();
modules_pack = NULL;
controls_pack->clear(); controls_pack->clear();
modules_pack = NULL;
if ( client() )
client()->unlock(); client()->unlock();
} }
@ -534,6 +539,8 @@ Chain::name ( const char *name )
if ( strip()->group() ) if ( strip()->group() )
{ {
if ( strip()->group()->single() ) if ( strip()->group()->single() )
/* we are the owner of this group and its only member, so
* rename it */
strip()->group()->name(name); strip()->group()->name(name);
} }
@ -713,6 +720,8 @@ Chain::add_to_process_queue ( Module *m )
void void
Chain::build_process_queue ( void ) Chain::build_process_queue ( void )
{ {
client()->lock();
process_queue.clear(); process_queue.clear();
for ( int i = 0; i < modules(); ++i ) for ( int i = 0; i < modules(); ++i )
@ -780,6 +789,8 @@ Chain::build_process_queue ( void )
/* delete[] s; */ /* delete[] s; */
/* } */ /* } */
/* } */ /* } */
client()->unlock();
} }
void void

View File

@ -109,7 +109,7 @@ public:
bool can_support_input_channels ( int n ); bool can_support_input_channels ( int n );
int modules ( void ) const { return modules_pack->children(); } int modules ( void ) const { return modules_pack ? modules_pack->children() : 0; }
Module *module ( int n ) const { return (Module*)modules_pack->child( n ); } Module *module ( int n ) const { return (Module*)modules_pack->child( n ); }
void remove ( Controller_Module *m ); void remove ( Controller_Module *m );
void remove ( Module *m ); void remove ( Module *m );

View File

@ -96,8 +96,6 @@ Controller_Module::~Controller_Module ( )
/* shutdown JACK port, if we have one */ /* shutdown JACK port, if we have one */
mode( GUI ); mode( GUI );
// disconnect();
} }
void void

View File

@ -56,6 +56,15 @@ Group::~Group ( )
{ {
DMESSAGE( "Destroying group" ); DMESSAGE( "Destroying group" );
for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
i != strips.end();
i++ )
{
/* avoid a use after free during project close when the group
* may be destroyed before its member strips are */
(*i)->clear_group();
}
if ( _name ) if ( _name )
free( _name ); free( _name );
@ -100,6 +109,8 @@ Group::set ( Log_Entry &e )
void void
Group::latency ( jack_latency_callback_mode_t mode ) Group::latency ( jack_latency_callback_mode_t mode )
{
if ( trylock() )
{ {
for ( std::list<Mixer_Strip*>::iterator i = strips.begin(); for ( std::list<Mixer_Strip*>::iterator i = strips.begin();
i != strips.end(); i != strips.end();
@ -108,6 +119,8 @@ Group::latency ( jack_latency_callback_mode_t mode )
if ( (*i)->chain() ) if ( (*i)->chain() )
(*i)->chain()->set_latency(mode == JackCaptureLatency ? JACK::Port::Input : JACK::Port::Output ); (*i)->chain()->set_latency(mode == JackCaptureLatency ? JACK::Port::Input : JACK::Port::Output );
} }
unlock();
}
} }
/* THREAD: RT */ /* THREAD: RT */
@ -208,8 +221,9 @@ Group::process ( nframes_t nframes )
void void
Group::recal_load_coef ( void ) Group::recal_load_coef ( void )
{ {
_load_coef = 1.0f / ( nframes() / (float)sample_rate() * 1000000.0 ); _load_coef = 1.0f / ( nframes() / (float)sample_rate() * 1000000.0f );
} }
int int
Group::sample_rate_changed ( nframes_t srate ) Group::sample_rate_changed ( nframes_t srate )
{ {
@ -273,6 +287,7 @@ void
Group::add ( Mixer_Strip *o ) Group::add ( Mixer_Strip *o )
{ {
lock(); lock();
if ( ! active() ) if ( ! active() )
{ {
/* to call init */ /* to call init */
@ -280,10 +295,12 @@ Group::add ( Mixer_Strip *o )
name(n); name(n);
free(n); free(n);
} }
if ( o->chain() ) if ( o->chain() )
o->chain()->thaw_ports(); o->chain()->thaw_ports();
strips.push_back(o); strips.push_back(o);
unlock(); unlock();
} }
@ -291,13 +308,15 @@ void
Group::remove ( Mixer_Strip *o ) Group::remove ( Mixer_Strip *o )
{ {
lock(); lock();
strips.remove(o); strips.remove(o);
if ( o->chain() ) if ( o->chain() )
o->chain()->freeze_ports(); o->chain()->freeze_ports();
if ( strips.size() == 0 && active() ) if ( strips.size() == 0 && active() )
{
Client::close(); Client::close();
}
unlock(); unlock();
} }

View File

@ -97,6 +97,8 @@ public:
void add (Mixer_Strip*); void add (Mixer_Strip*);
void remove (Mixer_Strip*); void remove (Mixer_Strip*);
int children ( void ) const { return strips.size(); }
/* Engine *engine ( void ) { return _engine; } */ /* Engine *engine ( void ) { return _engine; } */
}; };

View File

@ -821,8 +821,6 @@ void Mixer::remove ( Mixer_Strip *ms )
mixer_strips->remove( ms ); mixer_strips->remove( ms );
ms->group()->remove( ms );
if ( parent() ) if ( parent() )
parent()->redraw(); parent()->redraw();
} }

View File

@ -73,6 +73,7 @@ Mixer_Strip::Mixer_Strip( const char *strip_name ) : Fl_Group( 0, 0, 120, 600 )
init(); init();
/* create single member group */
_group = new Group(strip_name, true); _group = new Group(strip_name, true);
_group->add( this ); _group->add( this );
@ -111,10 +112,26 @@ Mixer_Strip::~Mixer_Strip ( )
/* make sure this gets destroyed before the chain */ /* make sure this gets destroyed before the chain */
fader_tab->clear(); fader_tab->clear();
if ( _group )
{
_group->remove( this );
}
if ( _chain )
{
delete _chain; delete _chain;
_chain = NULL; _chain = NULL;
} }
if ( _group )
{
if ( 0 == _group->children() )
delete _group;
_group = NULL;
}
}
void void
@ -347,6 +364,7 @@ void Mixer_Strip::cb_handle(Fl_Widget* o, void* v) {
void void
Mixer_Strip::group ( Group *g ) Mixer_Strip::group ( Group *g )
{ {
/* FIXME: what is the intention here? */
if ( !g && _group && _group->single() ) if ( !g && _group && _group->single() )
return; return;

View File

@ -170,6 +170,7 @@ public:
Controller_Module *spatializer ( void ); Controller_Module *spatializer ( void );
Group *group ( void ) { return _group; } Group *group ( void ) { return _group; }
void clear_group ( void ) { _group = NULL; }
// int group ( void ) const; // int group ( void ) const;
void group ( Group * ); void group ( Group * );

View File

@ -105,19 +105,25 @@ Module::~Module ( )
{ {
Module *o = (Module*)control_input[i].connected_port()->module(); Module *o = (Module*)control_input[i].connected_port()->module();
if ( ! o->is_default() ) if ( !o )
{ {
DWARNING( "Programming error. Connected port has null module. %s %s",
label(),
control_input[i].connected_port()->name());
}
control_input[i].disconnect(); control_input[i].disconnect();
if ( o )
{
if ( ! o->is_default() )
{
DMESSAGE( "Deleting connected module %s", o->label() ); DMESSAGE( "Deleting connected module %s", o->label() );
delete o; delete o;
} }
else
{
control_input[i].disconnect();
} }
} }
control_input[i].destroy_osc_port(); control_input[i].destroy_osc_port();
@ -125,6 +131,9 @@ Module::~Module ( )
for ( unsigned int i = 0; i < control_output.size(); ++i ) for ( unsigned int i = 0; i < control_output.size(); ++i )
control_output[i].disconnect(); control_output[i].disconnect();
aux_audio_output.clear();
aux_audio_input.clear();
audio_input.clear(); audio_input.clear();
audio_output.clear(); audio_output.clear();
@ -1180,8 +1189,20 @@ Module::freeze_ports ( void )
for ( int i = 0; i < ncontrol_inputs(); ++i ) for ( int i = 0; i < ncontrol_inputs(); ++i )
{ {
if ( control_input[i].connected() ) if ( control_input[i].connected() )
{
if ( ! control_input[i].connected_port()->module() )
{
DWARNING( "Programming error. Connected port has null module. %s %s",
name(),
control_input[i].connected_port()->name());
}
else
{
control_input[i].connected_port()->module()->freeze_ports(); control_input[i].connected_port()->module()->freeze_ports();
} }
}
}
for ( unsigned int i = 0; i < aux_audio_input.size(); ++i ) for ( unsigned int i = 0; i < aux_audio_input.size(); ++i )
{ {

View File

@ -173,6 +173,9 @@ public:
virtual ~Port ( ) virtual ~Port ( )
{ {
/* FIXME: will this cause problems with cloning an instance? */
disconnect();
if ( _by_number_path ) if ( _by_number_path )
free( _by_number_path ); free( _by_number_path );
_by_number_path = NULL; _by_number_path = NULL;
@ -321,18 +324,8 @@ public:
/* disconnect from *all* connected ports */ /* disconnect from *all* connected ports */
void disconnect ( void ) void disconnect ( void )
{ {
if ( _connected.size() ) while ( _connected.size() )
{ disconnect(_connected.front());
for ( std::list<Port*>::iterator i = _connected.begin(); i != _connected.end(); i++ )
{
Port *p = *i;
/* iterator about to be invalidated... */
i = _connected.erase(i);
disconnect(p);
}
}
} }
void jack_port ( JACK::Port *v ) { _jack_port = v; } void jack_port ( JACK::Port *v ) { _jack_port = v; }