Achievements: Don't double-free login callback on request failure

Callback always runs.
pull/3782/head v0.1-11752
Stenzek 1 month ago
parent 5ee1d25690
commit 5fd3668090
No known key found for this signature in database

@ -2008,29 +2008,21 @@ bool Achievements::IsLoggedInOrLoggingIn()
return (IsLoggedIn() || s_state.login_request);
}
bool Achievements::LoginAsync(const char* username, const char* password, Error* error,
LoginCompletionCallback callback)
void Achievements::LoginAsync(const char* username, const char* password, LoginCompletionCallback callback)
{
auto lock = GetLock();
// We need to use a temporary client if achievements aren't currently active.
if (!s_state.client && !CreateClient(lock, true))
{
Error::SetString(error, "Failed to create client.");
return false;
callback(false, "Failed to create client.");
return;
}
// Callback always runs regardless of whether an async request was created.
LoginCompletionCallback* const callback_copy = new LoginCompletionCallback(std::move(callback));
if (!rc_client_begin_login_with_password(s_state.client, username, password,
RESOLVE_CLIENT_CALLBACK(ClientLoginWithPasswordCallback), callback_copy))
{
Error::SetString(error, "Failed to create login request.");
delete callback_copy;
return false;
}
// Login attempt started.
return true;
rc_client_begin_login_with_password(s_state.client, username, password,
RESOLVE_CLIENT_CALLBACK(ClientLoginWithPasswordCallback), callback_copy);
}
void Achievements::ClientLoginWithPasswordCallback(int result, const char* error_message, rc_client_t* client,

@ -107,7 +107,7 @@ bool DoState(StateWrapper& sw);
/// Attempts to log in to RetroAchievements using the specified credentials.
/// If the login is successful, the token returned by the server will be saved.
using LoginCompletionCallback = std::function<void(bool result, std::string&& error_message)>;
bool LoginAsync(const char* username, const char* password, Error* error, LoginCompletionCallback callback);
void LoginAsync(const char* username, const char* password, LoginCompletionCallback callback);
/// Logs out of RetroAchievements, clearing any credentials.
void Logout();

@ -5844,31 +5844,25 @@ void FullscreenUI::DrawAchievementsLoginWindow()
{
OpenBackgroundProgressDialog(LOGIN_PROGRESS_NAME, FSUI_STR("Logging in to RetroAchievements..."), 0, 0, 0);
static constexpr auto set_error = [](const std::string& description) {
s_settings_locals.achievements_login_error = std::make_unique<std::string>(fmt::format(
FSUI_FSTR("Login Failed.\nError: {}\nPlease check your username and password, and try again."), description));
};
if (Error error; !Achievements::LoginAsync(
s_settings_locals.achievements_login_username, s_settings_locals.achievements_login_password, &error,
[](bool result, std::string&& error_message) {
// callback runs on core thread
DebugAssert(Host::IsOnCoreThread());
VideoThread::RunOnThread([result, error_message = std::move(error_message)]() {
CloseBackgroundProgressDialog(LOGIN_PROGRESS_NAME);
if (result)
{
CloseFixedPopupDialog();
return;
}
Achievements::LoginAsync(
s_settings_locals.achievements_login_username, s_settings_locals.achievements_login_password,
[](bool result, std::string&& error_message) {
// callback runs on core thread
DebugAssert(Host::IsOnCoreThread());
VideoThread::RunOnThread([result, error_message = std::move(error_message)]() {
CloseBackgroundProgressDialog(LOGIN_PROGRESS_NAME);
if (result)
{
CloseFixedPopupDialog();
return;
}
set_error(error_message);
});
}))
{
set_error(error.GetDescription());
}
s_settings_locals.achievements_login_error = std::make_unique<std::string>(
fmt::format(FSUI_FSTR("Login Failed.\nError: {}\nPlease check your username and password, and try again."),
error_message));
});
});
}
if (HorizontalMenuButton(FSUI_ICONVSTR(ICON_FA_XMARK, "Cancel"), !is_logging_in))

@ -53,18 +53,15 @@ void AchievementLoginDialog::loginClicked()
// Use QPointer<> to safely check if the dialog still exists when the login finishes, since the callback
// runs on the core thread and we need to queue it back to the UI thread.
if (Error error; !Achievements::LoginAsync(
username.toUtf8().constData(), password.toUtf8().constData(), &error,
[dialog = QPointer(this)](bool result, std::string&& error_message) mutable {
DebugAssert(Host::IsOnCoreThread());
Host::RunOnUIThread([dialog = std::move(dialog), error_message = std::move(error_message), result]() {
if (dialog)
dialog->processLoginResult(result, QString::fromStdString(error_message));
});
}))
{
processLoginResult(false, QString::fromStdString(error.GetDescription()));
}
Achievements::LoginAsync(username.toUtf8().constData(), password.toUtf8().constData(),
[dialog = QPointer(this)](bool result, std::string&& error_message) mutable {
DebugAssert(Host::IsOnCoreThread());
Host::RunOnUIThread(
[dialog = std::move(dialog), error_message = std::move(error_message), result]() {
if (dialog)
dialog->processLoginResult(result, QString::fromStdString(error_message));
});
});
}
void AchievementLoginDialog::cancelClicked()

Loading…
Cancel
Save