Skip to content

Commit

Permalink
LinuxSyscalls: Fixes exit syscall
Browse files Browse the repository at this point in the history
if an application is using `exit` then it is usually a faulting
condition rather than cleanly exiting. When cleanly exiting
applications will typically use `exit_group` instead.

`exit` is useful to quickly cause a single thread to exit in a
multi-threaded environment as well, where `exit_group` will take down
the entire process group.

FEX had implemented this in a way that would do a double Stop signal,
cascading to a crash. When tied in to a crash handler, this could get
caught in a weird way.

This /should/ fix #4198, but I can't confirm locally. It looks like in
that issue that the steam install is slightly buggered (as evident by
missing srt-logger and steam-runtime-identify-library-abi).

This is a bug regardless so fix it and create a unittest. If it doesn't
fix the user's bug, then we have another workaround that will definitely
solve it.
  • Loading branch information
Sonicadvance1 committed Dec 8, 2024
1 parent 7472b21 commit beec203
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 3 deletions.
7 changes: 4 additions & 3 deletions Source/Tools/LinuxEmulation/LinuxSyscalls/Syscalls/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,9 +414,10 @@ void RegisterThread(FEX::HLE::SyscallHandler* Handler) {
}

ThreadObject->StatusCode = status;
FEX::HLE::_SyscallHandler->TM.StopThread(ThreadObject);

return 0;
FEX::HLE::_SyscallHandler->TM.DestroyThread(ThreadObject, true);
syscall(SYSCALL_DEF(exit), status);
// This will never be reached
std::terminate();
});

REGISTER_SYSCALL_IMPL_FLAGS(prctl, SyscallFlags::OPTIMIZETHROUGH | SyscallFlags::NOSYNCSTATEONENTRY,
Expand Down
35 changes: 35 additions & 0 deletions unittests/FEXLinuxTests/tests/syscalls/syscall_exit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include <catch2/catch_test_macros.hpp>

#include <unistd.h>
#include <sys/wait.h>
#include <sys/syscall.h>

TEST_CASE("fork - exit") {
int child_pid = ::fork();
if (child_pid == 0) {
::syscall(SYS_exit, 1);
// unreachable
std::terminate();
} else {
int status {};
int exited_child = ::waitpid(child_pid, &status, 0);
bool exited = WIFEXITED(status);
REQUIRE(WIFEXITED(status) == 1);
CHECK(WEXITSTATUS(status) == 1);
}
}

TEST_CASE("fork - signal") {
int child_pid = ::fork();
if (child_pid == 0) {
::syscall(SYS_tgkill, ::getpid(), ::gettid(), SIGKILL);
// unreachable
std::terminate();
} else {
int status {};
int exited_child = ::waitpid(child_pid, &status, 0);
bool exited = WIFEXITED(status);
REQUIRE(WIFSIGNALED(status) == 1);
CHECK(WTERMSIG(status) == SIGKILL);
}
}

0 comments on commit beec203

Please sign in to comment.