Clean up the backtrace code and make it use write() more safely.

This commit is contained in:
GoldenTails 2022-12-26 21:06:46 -06:00
parent 2df3fb53da
commit 50a34d85dd

View file

@ -258,68 +258,82 @@ SDL_bool framebuffer = SDL_FALSE;
UINT8 keyboard_started = false; UINT8 keyboard_started = false;
#ifdef UNIXBACKTRACE #ifdef UNIXBACKTRACE
#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string)
#define CRASHLOG_WRITE(string) if (fd != -1) write(fd, string, strlen(string)) // NOTE: if written ends up ever being -1, all further writes end up being cancelled.
#define CRASHLOG_STDERR_WRITE(string) \ // i figure an error is a reason to stop writing...
if (fd != -1)\ #define WRITE_FILE(string) \
write(fd, string, strlen(string));\ sourcelen = strlen(string); \
I_OutputMsg("%s", string) while (fd != -1 && (written != -1 && errno != EINTR) && written < sourcelen) \
written = write(fd, string, sourcelen);
#define WRITE_STDERR(string) \
I_OutputMsg("%s", string);
#define WRITE_ALL(string) \
WRITE_FILE(string); \
WRITE_STDERR(string);
static void write_backtrace(INT32 signal) static void write_backtrace(INT32 signal)
{ {
int fd = -1; int fd = -1;
size_t size; ssize_t written = 0;
ssize_t sourcelen = 0;
time_t rawtime; time_t rawtime;
struct tm timeinfo; struct tm timeinfo;
size_t size;
enum { BT_SIZE = 1024, STR_SIZE = 32 }; enum { BT_SIZE = 1024, STR_SIZE = 32 };
void *array[BT_SIZE]; void *funcptrs[BT_SIZE];
char timestr[STR_SIZE]; char timestr[STR_SIZE];
const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n"; const char *filename = va("%s" PATHSEP "%s", srb2home, "crash-log.txt");
const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr.
fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR); fd = open(filename, O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
if (fd == -1) if (fd == -1) // File handle error
I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n"); WRITE_STDERR("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
// Get the current time as a string. // Get the current time as a string.
time(&rawtime); time(&rawtime);
localtime_r(&rawtime, &timeinfo); localtime_r(&rawtime, &timeinfo);
strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo); strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo);
CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator WRITE_FILE("------------------------\n"); // Nice looking seperator
CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs. WRITE_ALL("\n"); // Newline to look nice for both outputs.
CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message WRITE_ALL("An error occurred within SRB2! Send this stack trace to someone who can help!\n");
STDERR_WRITE(error2); // Tell the user where the crash log is.
if (fd != -1) // If the crash log exists,
WRITE_STDERR("(Or find crash-log.txt in your SRB2 directory.)\n"); // tell the user where the crash log is.
// Tell the log when we crashed. // Tell the log when we crashed.
CRASHLOG_WRITE("Time of crash: "); WRITE_FILE("Time of crash: ");
CRASHLOG_WRITE(timestr); WRITE_FILE(timestr);
CRASHLOG_WRITE("\n"); WRITE_FILE("\n");
// Give the crash log the cause and a nice 'Backtrace:' thing // Give the crash log the cause and a nice 'Backtrace:' thing
// The signal is given to the user when the parent process sees we crashed. // The signal is given to the user when the parent process sees we crashed.
CRASHLOG_WRITE("Cause: "); WRITE_FILE("Cause: ");
CRASHLOG_WRITE(strsignal(signal)); WRITE_FILE(strsignal(signal));
CRASHLOG_WRITE("\n"); // Newline for the signal name WRITE_FILE("\n"); // Newline for the signal name
CRASHLOG_STDERR_WRITE("\nBacktrace:\n"); WRITE_ALL("\nBacktrace:\n");
// Flood the output and log with the backtrace // Flood the output and log with the backtrace
size = backtrace(array, BT_SIZE); size = backtrace(funcptrs, BT_SIZE);
backtrace_symbols_fd(array, size, fd); backtrace_symbols_fd(funcptrs, size, fd);
backtrace_symbols_fd(array, size, STDERR_FILENO); backtrace_symbols_fd(funcptrs, size, STDERR_FILENO);
CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) WRITE_FILE("\n"); // Write another newline to the log so it looks nice :)
close(fd); if (fd != -1) {
fsync(fd); // reaaaaally make sure we got that data written.
close(fd);
}
} }
#undef STDERR_WRITE #undef WRITE_FILE
#undef CRASHLOG_WRITE #undef WRITE_STDERR
#undef CRASHLOG_STDERR_WRITE #undef WRITE_ALL
#endif // UNIXBACKTRACE #endif // UNIXBACKTRACE
static void I_ReportSignal(int num, int coredumped) static void I_ReportSignal(int num, int coredumped)