Compare commits
7 Commits
e9e1bef89c
...
6fc02e042a
Author | SHA1 | Date | |
---|---|---|---|
6fc02e042a | |||
620810d720 | |||
32ada00b72 | |||
dc795ff491 | |||
5f6a659fa1 | |||
d82b3f809b | |||
96a213ec5c |
@ -1 +1,2 @@
|
||||
target_compile_definitions(moon PRIVATE LOCKED_VALUE_DEBUG)
|
||||
target_compile_options(moon PRIVATE -fsanitize=undefined)
|
||||
|
@ -97,12 +97,27 @@ Result<void> init()
|
||||
CPU::idle_loop();
|
||||
}
|
||||
|
||||
// FIXME: Add a guard page to make sure the stack doesn't end up in random kernel memory. Also reclaim this memory after
|
||||
// leaving the init task.
|
||||
static constexpr u64 BOOTSTRAP_STACK_PAGES = 8;
|
||||
|
||||
// FIXME: Reclaim this memory as soon as we leave the init task (so as soon as the Scheduler runs a task switch)
|
||||
static u64 allocate_initial_kernel_stack()
|
||||
{
|
||||
u64 address = MemoryManager::alloc_for_kernel(BOOTSTRAP_STACK_PAGES + 1, MMU::ReadWrite | MMU::NoExecute).value();
|
||||
// First page is a guard page, the rest is stack.
|
||||
MMU::unmap(address); // Unmap (without deallocating VM) one guard page so that attempts to access it fail with a
|
||||
// non-present page fault.
|
||||
kdbgln("stack guard page: %p", (void*)address);
|
||||
|
||||
// The actual stack.
|
||||
Stack stack { address + ARCH_PAGE_SIZE, BOOTSTRAP_STACK_PAGES * ARCH_PAGE_SIZE };
|
||||
|
||||
return stack.top();
|
||||
}
|
||||
|
||||
extern "C" [[noreturn]] void _start()
|
||||
{
|
||||
Init::check_magic();
|
||||
Init::early_init();
|
||||
Stack stack { MemoryManager::alloc_for_kernel(8, MMU::ReadWrite | MMU::NoExecute).value(), 8 * ARCH_PAGE_SIZE };
|
||||
CPU::bootstrap_switch_stack(stack.top(), (void*)init_wrapper);
|
||||
u64 bootstrap_stack_top = allocate_initial_kernel_stack();
|
||||
CPU::bootstrap_switch_stack(bootstrap_stack_top, (void*)init_wrapper);
|
||||
}
|
||||
|
@ -84,4 +84,5 @@ void debug_log_impl(const char* format, va_list ap)
|
||||
{
|
||||
pure_cstyle_format(
|
||||
format, [](char c, void*) { console_write(&c, 1); }, nullptr, ap);
|
||||
console_write("\n", 1);
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ set(FREESTANDING_SOURCES
|
||||
src/DebugLog.cpp
|
||||
src/Heap.cpp
|
||||
src/Spinlock.cpp
|
||||
src/UBSAN.cpp
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
|
@ -19,6 +19,10 @@
|
||||
if (!(expr)) [[unlikely]] { __check_failed(location, message); } \
|
||||
} while (0)
|
||||
|
||||
// Fail with an error message and location.
|
||||
#define fail(message) __check_failed(SourceLocation::current(), message)
|
||||
#define fail_at(location, message) __check_failed(location, message)
|
||||
|
||||
// Like assert(), but always enabled.
|
||||
#define check(expr) \
|
||||
do { \
|
||||
|
@ -123,6 +123,20 @@ template <typename T> Result<SharedPtr<T>> adopt_shared(T* ptr)
|
||||
return SharedPtr<T> { ptr, ref_count };
|
||||
}
|
||||
|
||||
// NOTE: ptr is deleted if any of the adopt_shared* functions fail to construct a SharedPtr.
|
||||
template <typename T> Result<SharedPtr<T>> adopt_shared(T* ptr)
|
||||
{
|
||||
using RefCount = __detail::RefCount;
|
||||
|
||||
auto guard = make_scope_guard([ptr] { delete ptr; });
|
||||
|
||||
RefCount* const ref_count = TRY(make<RefCount>());
|
||||
|
||||
guard.deactivate();
|
||||
|
||||
return SharedPtr<T> { ptr, ref_count };
|
||||
}
|
||||
|
||||
template <typename T, class... Args> Result<SharedPtr<T>> make_shared(Args... args)
|
||||
{
|
||||
T* raw_ptr = TRY(make<T>(args...));
|
||||
|
74
luna/include/luna/UBSAN.h
Normal file
74
luna/include/luna/UBSAN.h
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include <luna/Types.h>
|
||||
|
||||
namespace UBSAN
|
||||
{
|
||||
struct SourceLocation
|
||||
{
|
||||
const char* file;
|
||||
u32 line;
|
||||
u32 column;
|
||||
};
|
||||
|
||||
struct TypeDescriptor
|
||||
{
|
||||
u16 kind;
|
||||
u16 info;
|
||||
char name[];
|
||||
};
|
||||
|
||||
namespace UBInfo
|
||||
{
|
||||
struct TypeMismatchInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* type;
|
||||
usize alignment;
|
||||
u8 type_check_kind;
|
||||
};
|
||||
|
||||
struct TypeMismatchInfo_v1
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* type;
|
||||
u8 log_alignment;
|
||||
u8 type_check_kind;
|
||||
};
|
||||
|
||||
struct OverflowInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* type;
|
||||
};
|
||||
|
||||
struct UnreachableInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
};
|
||||
|
||||
struct OutOfBoundsInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* array_type;
|
||||
TypeDescriptor* index_type;
|
||||
};
|
||||
|
||||
struct InvalidValueInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* type;
|
||||
};
|
||||
|
||||
struct ShiftOutOfBoundsInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
TypeDescriptor* lhs_type;
|
||||
TypeDescriptor* rhs_type;
|
||||
};
|
||||
|
||||
struct PointerOverflowInfo
|
||||
{
|
||||
SourceLocation location;
|
||||
};
|
||||
}
|
||||
}
|
121
luna/src/UBSAN.cpp
Normal file
121
luna/src/UBSAN.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include <luna/Check.h>
|
||||
#include <luna/DebugLog.h>
|
||||
#include <luna/SourceLocation.h>
|
||||
#include <luna/UBSAN.h>
|
||||
|
||||
using namespace UBSAN::UBInfo;
|
||||
|
||||
[[noreturn]] void ub_panic(SourceLocation caller = SourceLocation::current())
|
||||
{
|
||||
fail_at(caller, "Undefined behavior");
|
||||
}
|
||||
|
||||
#define DISPLAY(loc) loc.file, loc.line, loc.column
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void __ubsan_handle_builtin_unreachable(UnreachableInfo* info)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: __builtin_unreachable reached at %s:%d:%d", DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void __ubsan_handle_pointer_overflow(PointerOverflowInfo* info)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: pointer overflow occurred at %s:%d:%d", DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsInfo* info)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: shift out of bounds for type %s at %s:%d:%d", info->lhs_type->name, DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void __ubsan_handle_load_invalid_value(InvalidValueInfo* info)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: load invalid value for type %s at %s:%d:%d", info->type->name, DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void __ubsan_handle_out_of_bounds(OutOfBoundsInfo* info, usize index)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: out of bounds array (of type %s) access (index %zu of type %s) at %s:%d:%d",
|
||||
info->array_type->name, index, info->index_type->name, DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void ubsan_handle_generic_overflow(OverflowInfo* info, const char* overflow_type)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
dbgln("ubsan: %s overflow (value cannot fit into type %s) at %s:%d:%d", overflow_type, info->type->name,
|
||||
DISPLAY(location));
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
#define UBSAN_OVERFLOW_BINARY(operation) \
|
||||
void __ubsan_handle_##operation##_overflow(OverflowInfo* info, usize, usize) \
|
||||
{ \
|
||||
ubsan_handle_generic_overflow(info, #operation); \
|
||||
}
|
||||
|
||||
#define UBSAN_OVERFLOW_UNARY(operation) \
|
||||
void __ubsan_handle_##operation##_overflow(OverflowInfo* info, usize) \
|
||||
{ \
|
||||
ubsan_handle_generic_overflow(info, #operation); \
|
||||
}
|
||||
|
||||
UBSAN_OVERFLOW_BINARY(add);
|
||||
UBSAN_OVERFLOW_BINARY(sub);
|
||||
UBSAN_OVERFLOW_BINARY(mul);
|
||||
UBSAN_OVERFLOW_UNARY(negate);
|
||||
UBSAN_OVERFLOW_BINARY(divrem);
|
||||
|
||||
#define is_aligned(value, alignment) !(value & (alignment - 1))
|
||||
|
||||
const char* g_type_check_kinds[] = {
|
||||
"load of",
|
||||
"store to",
|
||||
"reference binding to",
|
||||
"member access within",
|
||||
"member call on",
|
||||
"constructor call on",
|
||||
"downcast of",
|
||||
"downcast of",
|
||||
"upcast of",
|
||||
"cast to virtual base of",
|
||||
};
|
||||
|
||||
void __ubsan_handle_type_mismatch(TypeMismatchInfo* info, usize pointer)
|
||||
{
|
||||
const auto& location = info->location;
|
||||
|
||||
if (pointer == 0) { dbgln("ubsan: null pointer access at %s:%d:%d", DISPLAY(location)); }
|
||||
else if (info->alignment != 0 && is_aligned(pointer, info->alignment))
|
||||
{
|
||||
dbgln("ubsan: unaligned pointer access (address %p) at %s:%d:%d", (void*)pointer, DISPLAY(location));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbgln("ubsan: %s address %p with insufficient space for object of type %s at %s:%d:%d",
|
||||
g_type_check_kinds[info->type_check_kind], (void*)pointer, info->type->name, DISPLAY(location));
|
||||
}
|
||||
ub_panic();
|
||||
}
|
||||
|
||||
void __ubsan_handle_type_mismatch_v1(TypeMismatchInfo_v1* v1_info, usize pointer)
|
||||
{
|
||||
TypeMismatchInfo info = {
|
||||
.location = v1_info->location,
|
||||
.type = v1_info->type,
|
||||
.alignment = 1UL << v1_info->log_alignment,
|
||||
.type_check_kind = v1_info->type_check_kind,
|
||||
};
|
||||
__ubsan_handle_type_mismatch(&info, pointer);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user