aboutsummaryrefslogtreecommitdiff
path: root/lib/mlibc/options/internal/generic/ubsan.cpp
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2024-03-07 17:28:00 -0500
committerIan Moffett <ian@osmora.org>2024-03-07 17:28:32 -0500
commitbd5969fc876a10b18613302db7087ef3c40f18e1 (patch)
tree7c2b8619afe902abf99570df2873fbdf40a4d1a1 /lib/mlibc/options/internal/generic/ubsan.cpp
parenta95b38b1b92b172e6cc4e8e56a88a30cc65907b0 (diff)
lib: Add mlibc
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'lib/mlibc/options/internal/generic/ubsan.cpp')
-rw-r--r--lib/mlibc/options/internal/generic/ubsan.cpp254
1 files changed, 254 insertions, 0 deletions
diff --git a/lib/mlibc/options/internal/generic/ubsan.cpp b/lib/mlibc/options/internal/generic/ubsan.cpp
new file mode 100644
index 0000000..3491729
--- /dev/null
+++ b/lib/mlibc/options/internal/generic/ubsan.cpp
@@ -0,0 +1,254 @@
+#include <limits.h>
+#include <mlibc/debug.hpp>
+
+#define FMT(obj) format_object((obj), opts, formatter)
+
+#define LOG_NAME_LOC(name, loc) "ubsan: " name " at " << loc << "\n "
+#define LOG_LHS_RHS(lhs, rhs) "LHS = " << (lhs) << ", RHS = " << (rhs)
+
+struct SourceLocation {
+ const char *filename;
+ uint32_t line;
+ uint32_t column;
+};
+
+template<class F>
+void format_object(const SourceLocation &loc, frg::format_options opts, F &formatter) {
+ FMT(loc.filename);
+ FMT(":");
+ FMT(loc.line);
+ FMT(":");
+ FMT(loc.column);
+}
+
+using ValueHandle = uintptr_t;
+
+struct TypeDescriptor {
+ enum class Kind : uint16_t {
+ Integer = 0x0000,
+ Float = 0x0001,
+ Unknown = 0xffff
+ } kind;
+
+ uint16_t info;
+ char name[];
+
+ unsigned bitWidthInt() const {
+ return 1 << (info >> 1);
+ }
+
+ bool isInlineInt() const {
+ if (kind != Kind::Integer)
+ return false;
+
+ auto inlineBits = sizeof(ValueHandle) * CHAR_BIT;
+ auto valueBits = bitWidthInt();
+ return inlineBits <= valueBits;
+ }
+
+ bool isSigned() const {
+ return info & 1;
+ }
+};
+
+template<class F>
+void format_object(const TypeDescriptor &type, frg::format_options opts, F &formatter) {
+ FMT(type.name);
+}
+
+struct Value {
+ const TypeDescriptor &type;
+ ValueHandle val;
+
+ Value(const TypeDescriptor &type, ValueHandle val) : type(type), val(val) {}
+};
+
+template<class F>
+void format_object(const Value &val, frg::format_options opts, F &formatter) {
+ if (val.type.isInlineInt() && val.type.isSigned()) {
+ auto signedValue = static_cast<int64_t>(val.val);
+ FMT(signedValue);
+ } else if (val.type.isInlineInt() && !val.type.isSigned()) {
+ auto unsignedValue = static_cast<uint64_t>(val.val);
+ FMT(unsignedValue);
+ }
+
+ FMT(" (");
+ FMT(val.type);
+ FMT(")");
+}
+
+
+// --- Hook implementations ---
+
+struct TypeMismatch {
+ SourceLocation loc;
+ const TypeDescriptor &type;
+ unsigned char logAlignment;
+ unsigned char kind;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_type_mismatch_v1(TypeMismatch *tm, ValueHandle pointer) {
+ // TODO: Make this print more information.
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("type mismatch", tm->loc)
+ << "accessed address " << (void *)pointer << " but type "
+ << tm->type << " requires alignment " << (1 << tm->logAlignment)
+ << frg::endlog;
+}
+
+struct PointerOverflowData {
+ SourceLocation loc;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_pointer_overflow(PointerOverflowData *pod, ValueHandle base, ValueHandle result) {
+ (void)base;
+ (void)result;
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("pointer overflow", pod->loc)
+ << frg::endlog;
+}
+
+struct InvalidValueData {
+ SourceLocation loc;
+ const TypeDescriptor &type;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_load_invalid_value(InvalidValueData *ivd, ValueHandle value) {
+ (void)value;
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("load of invalid value", ivd->loc)
+ << frg::endlog;
+}
+
+struct OverflowData {
+ SourceLocation loc;
+ const TypeDescriptor &type;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_add_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("add overflowed ", od->loc)
+ << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
+ << frg::endlog;
+}
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_sub_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("sub overflowed", od->loc)
+ << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
+ << frg::endlog;
+}
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_mul_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("mul overflowed", od->loc)
+ << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
+ << frg::endlog;
+}
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_divrem_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("divrem overflowed", od->loc)
+ << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
+ << frg::endlog;
+}
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_negate_overflow(OverflowData *od, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("negate overflowed", od->loc)
+ << LOG_LHS_RHS(Value(od->type, lhs), Value(od->type, rhs))
+ << frg::endlog;
+}
+
+struct ShiftOutOfBoundsData {
+ SourceLocation loc;
+ const TypeDescriptor &lhsType;
+ const TypeDescriptor &rhsType;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData *soob, ValueHandle lhs, ValueHandle rhs) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("shift out of bounds", soob->loc)
+ << LOG_LHS_RHS(Value(soob->lhsType, lhs), Value(soob->rhsType, rhs))
+ << frg::endlog;
+}
+
+struct OutOfBoundsData {
+ SourceLocation loc;
+ const TypeDescriptor &arrayType;
+ const TypeDescriptor &indexType;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_out_of_bounds(OutOfBoundsData *oobd, ValueHandle data) {
+ (void)data;
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("out of bounds access", oobd->loc)
+ << frg::endlog;
+}
+
+struct UnreachableData {
+ SourceLocation loc;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_builtin_unreachable(UnreachableData *ubd) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("reached __builtin_unreachable()", ubd->loc)
+ << frg::endlog;
+}
+
+struct InvalidBuiltinData {
+ SourceLocation loc;
+ unsigned char kind;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_invalid_builtin(InvalidBuiltinData *ibd) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("reached invalid builtin", ibd->loc)
+ << frg::endlog;
+}
+
+struct VLABoundData {
+ SourceLocation loc;
+ const TypeDescriptor &type;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_vla_bound_not_positive(VLABoundData *vlabd) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("VLA bound not positive", vlabd->loc)
+ << frg::endlog;
+}
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_missing_return(UnreachableData *data) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("reached end of a value-returning function without returning a value", data->loc)
+ << frg::endlog;
+}
+
+struct NonNullArgData {
+ SourceLocation loc;
+ SourceLocation attr_loc;
+ int arg_index;
+};
+
+extern "C" [[gnu::visibility("hidden")]]
+void __ubsan_handle_nonnull_arg(NonNullArgData *data) {
+ mlibc::panicLogger()
+ << LOG_NAME_LOC("null pointer passed to non-null argument", data->loc)
+ << "argument " << data->arg_index << " is required to be non-null in "
+ << data->attr_loc << frg::endlog;
+}