summaryrefslogtreecommitdiff
path: root/src/debug/crash/SignalSafe.hpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2025-12-03 16:01:45 +0000
committerGitHub <noreply@github.com>2025-12-03 16:01:45 +0000
commit93e5e92b0ae7809ee0f64d94d51e210c476ee823 (patch)
tree096ff92094b899ee6ed138951caf9e735a148378 /src/debug/crash/SignalSafe.hpp
parent3cf0280b11f370c11e6839275e547779a33f4a19 (diff)
crashReporter: cleanup code (#12534)
various code cleanups, reorders, move off of global NS
Diffstat (limited to 'src/debug/crash/SignalSafe.hpp')
-rw-r--r--src/debug/crash/SignalSafe.hpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/debug/crash/SignalSafe.hpp b/src/debug/crash/SignalSafe.hpp
new file mode 100644
index 00000000..8ec967fe
--- /dev/null
+++ b/src/debug/crash/SignalSafe.hpp
@@ -0,0 +1,203 @@
+#pragma once
+
+#include "defines.hpp"
+#include <cstring>
+
+namespace SignalSafe {
+ template <uint16_t N>
+ class CMaxLengthCString {
+ public:
+ CMaxLengthCString() {
+ m_str[0] = '\0';
+ }
+
+ void operator+=(char const* rhs) {
+ write(rhs, strlen(rhs));
+ }
+
+ void write(char const* data, size_t len) {
+ if (m_boundsExceeded || m_strPos + len >= N) {
+ m_boundsExceeded = true;
+ return;
+ }
+ memcpy(m_str + m_strPos, data, len);
+ m_strPos += len;
+ m_str[m_strPos] = '\0';
+ }
+
+ void write(char c) {
+ if (m_boundsExceeded || m_strPos + 1 >= N) {
+ m_boundsExceeded = true;
+ return;
+ }
+ m_str[m_strPos] = c;
+ m_strPos++;
+ }
+
+ void writeNum(size_t num) {
+ size_t d = 1;
+
+ while (num / 10 >= d) {
+ d *= 10;
+ }
+
+ while (num > 0) {
+ char c = '0' + (num / d);
+ write(c);
+ num %= d;
+ d /= 10;
+ }
+ }
+
+ char const* getStr() {
+ return m_str;
+ }
+
+ bool boundsExceeded() {
+ return m_boundsExceeded;
+ }
+
+ private:
+ char m_str[N];
+ size_t m_strPos = 0;
+ bool m_boundsExceeded = false;
+ };
+
+ template <uint16_t BUFSIZE>
+ class CBufFileWriter {
+ public:
+ CBufFileWriter(int fd_) : m_fd(fd_) {
+ ;
+ }
+
+ ~CBufFileWriter() {
+ flush();
+ }
+
+ void write(char const* data, size_t len) {
+ while (len > 0) {
+ size_t to_add = std::min(len, sc<size_t>(BUFSIZE) - m_writeBufPos);
+ memcpy(m_writeBuf + m_writeBufPos, data, to_add);
+ data += to_add;
+ len -= to_add;
+ m_writeBufPos += to_add;
+ if (m_writeBufPos == BUFSIZE)
+ flush();
+ }
+ }
+
+ void write(char c) {
+ if (m_writeBufPos == BUFSIZE)
+ flush();
+ m_writeBuf[m_writeBufPos] = c;
+ m_writeBufPos++;
+ }
+
+ void operator+=(char const* str) {
+ write(str, strlen(str));
+ }
+
+ void operator+=(std::string_view str) {
+ write(str.data(), str.size());
+ }
+
+ void operator+=(char c) {
+ write(c);
+ }
+
+ void writeNum(size_t num) {
+ size_t d = 1;
+
+ while (num / 10 >= d) {
+ d *= 10;
+ }
+
+ while (num > 0) {
+ char c = '0' + (num / d);
+ write(c);
+ num %= d;
+ d /= 10;
+ }
+ }
+
+ void writeCmdOutput(const char* cmd) {
+ int pipefd[2];
+ if (pipe(pipefd) < 0) {
+ *this += "<pipe(pipefd) failed with";
+ writeNum(errno);
+ *this += ">\n";
+ return;
+ }
+
+ // terminate child instead of waiting
+ {
+ struct sigaction act;
+ act.sa_handler = SIG_DFL;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NOCLDWAIT;
+#ifdef SA_RESTORER
+ act.sa_restorer = NULL;
+#endif
+ sigaction(SIGCHLD, &act, nullptr);
+ }
+
+ const pid_t pid = fork();
+
+ if (pid < 0) {
+ *this += "<fork() failed with ";
+ writeNum(errno);
+ *this += ">\n";
+ return;
+ }
+
+ if (pid == 0) {
+ close(pipefd[0]);
+ dup2(pipefd[1], STDOUT_FILENO);
+ char const* const argv[] = {"/bin/sh", "-c", cmd, nullptr};
+ execv("/bin/sh", cc<char* const*>(argv));
+
+ CBufFileWriter<64> failmsg(pipefd[1]);
+ failmsg += "<execv(";
+ failmsg += cmd;
+ failmsg += ") resulted in errno ";
+ failmsg.write(errno);
+ failmsg += ">\n";
+ close(pipefd[1]);
+ abort();
+ } else {
+ close(pipefd[1]);
+ int64_t len = 0;
+ char readbuf[256];
+ while ((len = read(pipefd[0], readbuf, 256)) > 0) {
+ write(readbuf, len);
+ }
+ if (len < 0) {
+ *this += "<interrupted, read() resulted in errno ";
+ writeNum(errno);
+ *this += ">\n";
+ }
+ close(pipefd[0]);
+ }
+ }
+
+ void flush() {
+ size_t i = 0;
+ while (i < m_writeBufPos) {
+ auto written = ::write(m_fd, m_writeBuf + i, m_writeBufPos - i);
+ if (written <= 0) {
+ return;
+ }
+ i += written;
+ }
+ m_writeBufPos = 0;
+ }
+
+ private:
+ char m_writeBuf[BUFSIZE] = {0};
+ size_t m_writeBufPos = 0;
+ int m_fd = 0;
+ };
+
+ char const* getenv(const char* name);
+ char const* strsignal(int sig);
+}