Compare commits

..

No commits in common. "6fc02e042afcd26d7fa74117da2bcb74645a1642" and "e9e1bef89c7930a1ccfd78c7166ae8b4af19eb27" have entirely different histories.

8 changed files with 4 additions and 235 deletions

View File

@ -1,2 +1 @@
target_compile_definitions(moon PRIVATE LOCKED_VALUE_DEBUG) target_compile_definitions(moon PRIVATE LOCKED_VALUE_DEBUG)
target_compile_options(moon PRIVATE -fsanitize=undefined)

View File

@ -97,27 +97,12 @@ Result<void> init()
CPU::idle_loop(); CPU::idle_loop();
} }
static constexpr u64 BOOTSTRAP_STACK_PAGES = 8; // 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.
// 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() extern "C" [[noreturn]] void _start()
{ {
Init::check_magic(); Init::check_magic();
Init::early_init(); Init::early_init();
u64 bootstrap_stack_top = allocate_initial_kernel_stack(); Stack stack { MemoryManager::alloc_for_kernel(8, MMU::ReadWrite | MMU::NoExecute).value(), 8 * ARCH_PAGE_SIZE };
CPU::bootstrap_switch_stack(bootstrap_stack_top, (void*)init_wrapper); CPU::bootstrap_switch_stack(stack.top(), (void*)init_wrapper);
} }

View File

@ -84,5 +84,4 @@ void debug_log_impl(const char* format, va_list ap)
{ {
pure_cstyle_format( pure_cstyle_format(
format, [](char c, void*) { console_write(&c, 1); }, nullptr, ap); format, [](char c, void*) { console_write(&c, 1); }, nullptr, ap);
console_write("\n", 1);
} }

View File

@ -17,7 +17,6 @@ set(FREESTANDING_SOURCES
src/DebugLog.cpp src/DebugLog.cpp
src/Heap.cpp src/Heap.cpp
src/Spinlock.cpp src/Spinlock.cpp
src/UBSAN.cpp
) )
set(SOURCES set(SOURCES

View File

@ -19,10 +19,6 @@
if (!(expr)) [[unlikely]] { __check_failed(location, message); } \ if (!(expr)) [[unlikely]] { __check_failed(location, message); } \
} while (0) } 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. // Like assert(), but always enabled.
#define check(expr) \ #define check(expr) \
do { \ do { \

View File

@ -123,20 +123,6 @@ template <typename T> Result<SharedPtr<T>> adopt_shared(T* ptr)
return SharedPtr<T> { ptr, ref_count }; 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) template <typename T, class... Args> Result<SharedPtr<T>> make_shared(Args... args)
{ {
T* raw_ptr = TRY(make<T>(args...)); T* raw_ptr = TRY(make<T>(args...));

View File

@ -1,74 +0,0 @@
#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;
};
}
}

View File

@ -1,121 +0,0 @@
#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);
}
}