diff --git a/app/src/main/cpp/skyline/kernel/svc.cpp b/app/src/main/cpp/skyline/kernel/svc.cpp index 6879228a..cf4d48b8 100644 --- a/app/src/main/cpp/skyline/kernel/svc.cpp +++ b/app/src/main/cpp/skyline/kernel/svc.cpp @@ -2,6 +2,7 @@ // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #include +#include #include #include #include @@ -218,9 +219,7 @@ namespace skyline::kernel::svc { void ExitProcess(const DeviceState &state) { state.logger->Debug("Exiting process"); - if (state.thread->id) - state.process->Kill(false); - std::longjmp(state.thread->originalCtx, true); + throw nce::NCE::ExitException(true); } constexpr i32 IdealCoreDontCare{-1}; @@ -279,7 +278,7 @@ namespace skyline::kernel::svc { void ExitThread(const DeviceState &state) { state.logger->Debug("Exiting current thread"); - std::longjmp(state.thread->originalCtx, true); + throw nce::NCE::ExitException(false); } void SleepThread(const DeviceState &state) { diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 62b229d5..af01527f 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -14,6 +14,12 @@ #include "nce.h" namespace skyline::nce { + NCE::ExitException::ExitException(bool killAllThreads) : killAllThreads(killAllThreads) {} + + const char *NCE::ExitException::what() const noexcept { + return killAllThreads ? "ExitProcess" : "ExitThread"; + } + void NCE::SvcHandler(u16 svcId, ThreadContext *ctx) { TRACE_EVENT_END("guest"); @@ -42,6 +48,12 @@ namespace skyline::nce { } abi::__cxa_end_catch(); // We call this prior to the longjmp to cause the exception object to be destroyed std::longjmp(state.thread->originalCtx, true); + } catch (const ExitException &e) { + if (e.killAllThreads && state.thread->id) { + signal::BlockSignal({SIGINT}); + state.process->Kill(false); + } + std::longjmp(state.thread->originalCtx, true); } catch (const std::exception &e) { if (svc) state.logger->ErrorNoPrefix("{} (SVC: {})\nStack Trace:{}", e.what(), svc.name, state.loader->GetStackTrace()); @@ -94,7 +106,7 @@ namespace skyline::nce { std::ifstream status("/proc/self/status"); constexpr std::string_view TracerPidTag = "TracerPid:"; - for (std::string line; std::getline(status, line); ) { + for (std::string line; std::getline(status, line);) { if (line.starts_with(TracerPidTag)) { line = line.substr(TracerPidTag.size()); diff --git a/app/src/main/cpp/skyline/nce.h b/app/src/main/cpp/skyline/nce.h index 7fab9afd..de8848c0 100644 --- a/app/src/main/cpp/skyline/nce.h +++ b/app/src/main/cpp/skyline/nce.h @@ -17,6 +17,21 @@ namespace skyline::nce { static void SvcHandler(u16 svcId, ThreadContext *ctx); public: + /** + * @brief An exception which causes the throwing thread to exit alongside all threads optionally + * @note Exiting must not be performed directly as it could leak temporary objects on the stack by not calling their destructors + */ + struct ExitException : std::exception { + bool killAllThreads; //!< If to kill all threads or just the throwing thread + + ExitException(bool killAllThreads = true); + + virtual const char* what() const noexcept; + }; + + /** + * @brief Handles any signals in the NCE threads + */ static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls); NCE(const DeviceState &state); diff --git a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp index f95f2375..410ebd14 100644 --- a/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp +++ b/app/src/main/cpp/skyline/services/am/controller/ISelfController.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) +#include #include #include #include "ISelfController.h" @@ -9,10 +10,7 @@ namespace skyline::service::am { ISelfController::ISelfController(const DeviceState &state, ServiceManager &manager) : libraryAppletLaunchableEvent(std::make_shared(state, false)), accumulatedSuspendedTickChangedEvent(std::make_shared(state, false)), hosbinder(manager.CreateOrGetService("dispdrv")), BaseService(state, manager) {} Result ISelfController::Exit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) { - if (state.thread->id) - state.process->Kill(false); - std::longjmp(state.thread->originalCtx, true); - return {}; + throw nce::NCE::ExitException(true); } Result ISelfController::LockExit(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {