13
0

startup: fix use-after free of startup FSM object

In some startup flows, the entire loading process happens inside
StartupFSM::start(). In others, that call gets things moving but
we return from it and loading is not complete until later.

Deleting the StartupFSM while still inside the ::start() call
led to a use-after-free error. This new code will leak the StartupFSM
in some startup flows.
This commit is contained in:
Paul Davis 2023-09-18 16:26:41 -06:00
parent bc91ea3c42
commit 5122036054
3 changed files with 23 additions and 3 deletions

View File

@ -550,8 +550,6 @@ ARDOUR_UI::sfsm_response (StartupFSM::Result r)
if (load_session_from_startup_fsm () == 0) {
startup_done ();
delete startup_fsm;
startup_fsm = 0;
} else {
DEBUG_TRACE (DEBUG::GuiStartup, "FSM reset\n");
startup_fsm->reset ();
@ -621,6 +619,11 @@ ARDOUR_UI::starting ()
*/
startup_fsm->start ();
if (startup_fsm->complete()) {
delete startup_fsm;
startup_fsm = 0;
}
}
return 0;
@ -692,8 +695,13 @@ ARDOUR_UI::load_session_from_startup_fsm ()
return 0;
}
return load_session (session_path, session_name, session_template);
int ret = load_session (session_path, session_name, session_template);
if (!ret) {
startup_fsm->set_complete ();
}
return ret;
}
void

View File

@ -133,6 +133,10 @@ StartupFSM::start ()
DEBUG_TRACE (DEBUG::GuiStartup, string_compose (X_("State at startup: %1\n"), enum_2_string (_state)));
switch (_state) {
case NotWaiting:
abort();
break;
case WaitingForPreRelease:
show_pre_release_dialog ();
break;
@ -199,6 +203,10 @@ StartupFSM::dialog_response_handler (int response, StartupFSM::DialogID dialog_i
*/
switch (_state) {
case NotWaiting:
abort();
break;
case WaitingForPreRelease:
switch (dialog_id) {
case ApplicationPseudoDialog:

View File

@ -50,6 +50,7 @@ class StartupFSM : public sigc::trackable
};
enum MainState {
NotWaiting,
WaitingForPreRelease,
WaitingForNewUser,
WaitingForSessionPath,
@ -83,6 +84,9 @@ class StartupFSM : public sigc::trackable
bool brand_new_user() const { return new_user; }
void handle_path (std::string const & path);
bool complete() const { return _state == NotWaiting; }
void set_complete () { _state = NotWaiting; }
private:
bool new_user;
bool new_session_required;