mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 06:42:07 +01:00
Add an abort handler and preload it on Linux (#1456)
Some native code (CEF) may cause SIGTRAP to be sent on fatal errors, which brings down the entire server. Instead only kill the thread and attempt to continue.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,3 +20,4 @@ scripts/OpenJDK*
|
||||
scripts/zulu*
|
||||
scripts/electron-*
|
||||
scripts/rcedit-*
|
||||
scripts/resources/*.so
|
||||
|
||||
@@ -38,6 +38,10 @@ main() {
|
||||
|
||||
download_launcher
|
||||
|
||||
if [ ! -f scripts/resources/catch_abort.so ]; then
|
||||
gcc -fPIC -I$JAVA_HOME/include -I$JAVA_HOME/include/linux -shared scripts/resources/catch_abort.c -lpthread -o scripts/resources/catch_abort.so
|
||||
fi
|
||||
|
||||
case "$OS" in
|
||||
debian-all)
|
||||
RELEASE="$RELEASE_NAME.deb"
|
||||
@@ -184,6 +188,7 @@ make_linux_bundle() {
|
||||
cp "$JAR" "$RELEASE_NAME/bin/Suwayomi-Server.jar"
|
||||
cp "scripts/resources/suwayomi-launcher.sh" "$RELEASE_NAME/"
|
||||
cp "scripts/resources/suwayomi-server.sh" "$RELEASE_NAME/"
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/bin/"
|
||||
|
||||
tar -I "gzip -9" -cvf "$RELEASE" "$RELEASE_NAME/"
|
||||
}
|
||||
@@ -208,6 +213,7 @@ make_deb_package() {
|
||||
mv "$RELEASE_NAME/Suwayomi-Launcher.jar" "$RELEASE_NAME/$source_dir/Suwayomi-Launcher.jar"
|
||||
cp "$JAR" "$RELEASE_NAME/$source_dir/Suwayomi-Server.jar"
|
||||
copy_linux_package_assets_to "$RELEASE_NAME/$source_dir/"
|
||||
cp "scripts/resources/catch_abort.so" "$RELEASE_NAME/$source_dir/"
|
||||
tar -I "gzip" -C "$RELEASE_NAME/" -cvf "$upstream_source" "$source_dir"
|
||||
|
||||
cp -r "scripts/resources/deb/" "$RELEASE_NAME/$source_dir/debian/"
|
||||
|
||||
62
scripts/resources/catch_abort.c
Normal file
62
scripts/resources/catch_abort.c
Normal file
@@ -0,0 +1,62 @@
|
||||
// Linux only:
|
||||
// Attempts to catch SIGTRAP, inform Java, then exit the thread instead of bringing down the whole process
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
#include <execinfo.h>
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
JavaVM *g_vm;
|
||||
|
||||
void load_vm() {
|
||||
if (g_vm) return;
|
||||
JavaVM *vms[1];
|
||||
jsize n = 0;
|
||||
// JNI_OnLoad won't be called when loaded via LD_PRELOAD, so attempt to find the VM now
|
||||
if (JNI_GetCreatedJavaVMs(vms, 1, &n) == JNI_OK && n > 0) {
|
||||
g_vm = vms[0];
|
||||
}
|
||||
}
|
||||
|
||||
jint throwThreadDeath(JNIEnv *env, char *message) {
|
||||
char *className = "java/lang/UnknownError";
|
||||
jclass exClass = (*env)->FindClass(env, className);
|
||||
if (exClass == NULL) return JNI_ERR;
|
||||
return (*env)->ThrowNew(env, exClass, message);
|
||||
}
|
||||
|
||||
void signalHandler(int signum, siginfo_t* si, void* uc) {
|
||||
void *retaddrs[64];
|
||||
int n = backtrace(retaddrs, sizeof(retaddrs) / sizeof(retaddrs[0]));
|
||||
printf("\n### ABORT :: Backtrace: ###\n");
|
||||
backtrace_symbols_fd(retaddrs, n, STDERR_FILENO);
|
||||
printf("### ABORT :: Exiting this thread. If this causes problems, please report the above backtrace to Suwayomi. ###\n\n");
|
||||
|
||||
load_vm();
|
||||
if (g_vm) {
|
||||
JNIEnv *env;
|
||||
jint getEnvStat = (*g_vm)->GetEnv(g_vm, (void**) &env, JNI_VERSION_1_2);
|
||||
if (getEnvStat == JNI_EDETACHED) (*g_vm)->AttachCurrentThread(g_vm, (void**) &env, NULL);
|
||||
jint exStat = throwThreadDeath(env, "SIGTRAP caught");
|
||||
if (exStat != 0) printf("Exception throwing failed: %d\n", exStat);
|
||||
(*g_vm)->DetachCurrentThread(g_vm);
|
||||
}
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
void dlmain() {
|
||||
struct sigaction sa = {0};
|
||||
sa.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||
sa.sa_sigaction = &signalHandler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
if (sigaction(SIGTRAP, &sa, NULL) != 0) {
|
||||
printf("[FATAL] sigaction failed\n");
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,4 @@ suwayomi-server.tmpfiles => usr/lib/tmpfiles.d/suwayomi-server.conf
|
||||
suwayomi-server.conf => etc/suwayomi/server.conf
|
||||
suwayomi-server.sh => usr/bin/suwayomi-server
|
||||
suwayomi-launcher.sh => usr/bin/suwayomi-launcher
|
||||
catch_abort.so usr/share/java/suwayomi-server/bin/
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LD_PRELOAD="/usr/share/java/suwayomi-server/bin/catch_abort.so"
|
||||
exec /usr/bin/java -jar /usr/share/java/suwayomi-server/bin/Suwayomi-Server.jar
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
export LD_PRELOAD="`realpath ./bin/catch_abort.so`"
|
||||
exec ./jre/bin/java -jar ./bin/Suwayomi-Server.jar
|
||||
|
||||
Reference in New Issue
Block a user