mirror of
https://github.com/XTXMarkets/ternfs.git
synced 2026-01-09 20:39:57 -06:00
...most notably we now produce fully static binaries in an alpine
image.
A few assorted thoughts:
* I really like static binaries, ideally I'd like to run EggsFS
deployments with just systemd scripts and a few binaries.
* Go already does this, which is great.
* C++ does not, which is less great.
* Linking statically against `glibc` works, but is unsupported.
Not only stuff like NSS (which `gethostbyname` requires)
straight up does not work, unless you build `glibc` with
unsupported and currently apparently broken flags
(`--enable-static-nss`), but also other stuff is subtly
broken (I couldn't remember exactly what was broken,
but see comments such as
<https://github.com/haskell/haskell-language-server/issues/2431#issuecomment-985880838>).
* So we're left with alternative libcs -- the most popular being
musl.
* The simplest way to build a C++ application using musl is to just
build on a system where musl is already the default libc -- such
as alpine linux.
The backtrace support is in a bit of a bad state. Exception stacktraces
work on musl, but DWARF seems to be broken on the normal release build.
Moreover, libunwind doesn't play well with musl's signal handler:
<https://maskray.me/blog/2022-04-10-unwinding-through-signal-handler>.
Keeping it working seems to be a bit of a chore, and I'm going to revisit
it later.
In the meantime, gdb stack traces do work fine.
122 lines
3.9 KiB
C++
122 lines
3.9 KiB
C++
#pragma once
|
|
|
|
#include <string.h>
|
|
#include <string>
|
|
#include <sstream>
|
|
|
|
#include "FormatTuple.hpp"
|
|
#include "strerror.h"
|
|
|
|
#define EGGS_EXCEPTION(...) EggsException(__LINE__, SHORT_FILE, removeTemplates(__PRETTY_FUNCTION__).c_str(), VALIDATE_FORMAT(__VA_ARGS__))
|
|
#define SYSCALL_EXCEPTION(...) SyscallException(__LINE__, SHORT_FILE, removeTemplates(__PRETTY_FUNCTION__).c_str(), errno, VALIDATE_FORMAT(__VA_ARGS__))
|
|
#define EXPLICIT_SYSCALL_EXCEPTION(rc, ...) SyscallException(__LINE__, SHORT_FILE, removeTemplates(__PRETTY_FUNCTION__).c_str(), rc, VALIDATE_FORMAT(__VA_ARGS__))
|
|
#define FATAL_EXCEPTION(...) FatalException(__LINE__, SHORT_FILE, removeTemplates(__PRETTY_FUNCTION__).c_str(), VALIDATE_FORMAT(__VA_ARGS__))
|
|
|
|
std::string removeTemplates(const std::string & s);
|
|
const char *translateErrno(int _errno);
|
|
|
|
class AbstractException : public std::exception {
|
|
public:
|
|
AbstractException();
|
|
const char * getStackTrace() const;
|
|
virtual const char *what() const throw() override = 0;
|
|
|
|
private:
|
|
char _stacktrace[4000];
|
|
};
|
|
|
|
|
|
class EggsException : public AbstractException {
|
|
public:
|
|
template <typename TFmt, typename ... Args>
|
|
EggsException(int line, const char *file, const char *function, TFmt fmt, Args ... args);
|
|
virtual const char *what() const throw() override;
|
|
|
|
private:
|
|
std::string _msg;
|
|
};
|
|
|
|
|
|
class SyscallException : public AbstractException {
|
|
public:
|
|
template <typename ... Args>
|
|
SyscallException(int line, const char *file, const char *function, int capturedErrno, const char *format, Args ... args);
|
|
virtual const char *what() const throw() override;
|
|
|
|
private:
|
|
int _errno;
|
|
std::string _msg;
|
|
};
|
|
|
|
|
|
class FatalException : public AbstractException {
|
|
public:
|
|
template <typename ... Args>
|
|
FatalException(int line, const char *file, const char *function, const char *format, Args ... args);
|
|
virtual const char *what() const throw() override;
|
|
|
|
private:
|
|
std::string _msg;
|
|
};
|
|
|
|
|
|
|
|
class AssertionException : public AbstractException {
|
|
public:
|
|
template <typename ... Args>
|
|
AssertionException(int line, const char *file, const char *function, const char *expr, const char* fmt, Args ... args);
|
|
AssertionException(int line, const char *file, const char *function, const char *expr) : AssertionException(line, file, function, expr, nullptr) {}
|
|
virtual const char *what() const throw() override { return _msg.c_str(); }
|
|
|
|
private:
|
|
std::string _msg;
|
|
};
|
|
|
|
template <typename TFmt, typename ... Args>
|
|
EggsException::EggsException(int line, const char *file, const char *function, TFmt fmt, Args ... args) {
|
|
|
|
std::stringstream ss;
|
|
ss << "EggsException(" << file << "@" << line << " in " << function << "):\n";
|
|
format_pack(ss, fmt, args...);
|
|
|
|
_msg = ss.str();
|
|
}
|
|
|
|
|
|
template <typename ... Args>
|
|
SyscallException::SyscallException(int line, const char *file, const char *function, int capturedErrno, const char *fmt, Args ... args) :
|
|
_errno(capturedErrno)
|
|
{
|
|
|
|
const char* errmsg = safe_strerror(_errno);
|
|
|
|
std::stringstream ss;
|
|
ss << "SyscallException(" << file << "@" << line << ", " << _errno << "/" << translateErrno(_errno) << "=" << errmsg << " in " << function << "):\n";
|
|
format_pack(ss, fmt, args...);
|
|
|
|
_msg = ss.str();
|
|
}
|
|
|
|
template <typename ... Args>
|
|
FatalException::FatalException(int line, const char *file, const char *function, const char *fmt, Args ... args) {
|
|
|
|
std::stringstream ss;
|
|
ss << "FatalException(" << file << "@" << line << " in " << function << "):\n";
|
|
format_pack(ss, fmt, args...);
|
|
|
|
_msg = ss.str();
|
|
}
|
|
|
|
|
|
template <typename ... Args>
|
|
AssertionException::AssertionException(int line, const char *file, const char *function, const char *expr, const char* fmt, Args ... args) {
|
|
std::stringstream ss;
|
|
ss << "AssertionException(" << file << "@" << line << " in " << function << "):\n";
|
|
ss << "Expected: " << expr;
|
|
if (fmt != nullptr && fmt[0] != '\0') {
|
|
ss << "\nMessage: ";
|
|
format_pack(ss, fmt, args...);
|
|
}
|
|
_msg = ss.str();
|
|
}
|