Skip to content

Commit

Permalink
kernel+userland: support build with undefined behavior sanitizer
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Nov 26, 2024
1 parent dd4e7ed commit dd6ef72
Show file tree
Hide file tree
Showing 8 changed files with 166 additions and 19 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,13 @@ jobs:
timeout-minutes: 3
- run: grub-file --is-x86-multiboot kernel/kernel
- run: make disk_image
ubsan:
runs-on: ubuntu-24.04
env:
CC: gcc
steps:
- uses: actions/checkout@v4
- run: sudo apt-get update && sudo apt-get install -y gcc-multilib cpio qemu-system-x86
- run: make EXTRA_CFLAGS="-Werror -fsanitize=undefined"
- run: make test
timeout-minutes: 5
11 changes: 11 additions & 0 deletions common/panic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include <stddef.h>
#include <stdnoreturn.h>

#define PANIC(...) panic(__FILE__, __LINE__, __VA_ARGS__)
#define UNREACHABLE() PANIC("Unreachable")
#define UNIMPLEMENTED() PANIC("Unimplemented")
#define ASSERT(cond) ((cond) ? (void)0 : PANIC("Assertion failed: " #cond))

noreturn void panic(const char* file, size_t line, const char* message, ...);
137 changes: 137 additions & 0 deletions common/ubsan.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include "panic.h"
#include <stdbool.h>
#include <stdint.h>

struct source_location {
const char* filename;
uint32_t line;
uint32_t column;
};

struct type_descriptor {
uint16_t kind;
uint16_t info;
char name[];
};

struct invalid_value_data {
struct source_location location;
const struct type_descriptor* type;
};

void __ubsan_handle_load_invalid_value(const struct invalid_value_data* data,
const void* ptr) {
(void)ptr;
PANIC("ubsan: load invalid value: type=%s", data->type->name);
}

struct overflow_data {
struct source_location location;
const struct type_descriptor* type;
};

void __ubsan_handle_add_overflow(const struct overflow_data* data,
const void* lhs, const void* rhs) {
(void)lhs;
(void)rhs;
PANIC("ubsan: add overflow: type=%s", data->type->name);
}

void __ubsan_handle_sub_overflow(const struct overflow_data* data,
const void* lhs, const void* rhs) {
(void)lhs;
(void)rhs;
PANIC("ubsan: sub overflow: type=%s", data->type->name);
}

void __ubsan_handle_negate_overflow(const struct overflow_data* data,
const void* ptr) {
(void)ptr;
PANIC("ubsan: negate overflow: type=%s", data->type->name);
}

void __ubsan_handle_mul_overflow(const struct overflow_data* data,
const void* lhs, const void* rhs) {
(void)lhs;
(void)rhs;
PANIC("ubsan: mul overflow: type=%s", data->type->name);
}

struct shift_out_of_bounds_data {
struct source_location location;
const struct type_descriptor* lhs_type;
const struct type_descriptor* rhs_type;
};

void __ubsan_handle_shift_out_of_bounds(
const struct shift_out_of_bounds_data* data, const void* lhs,
const void* rhs) {
(void)lhs;
(void)rhs;
PANIC("ubsan: shift out of bounds: lhs=%s rhs=%s", data->lhs_type->name,
data->rhs_type->name);
}

void __ubsan_handle_divrem_overflow(const struct overflow_data* data,
const void* lhs, const void* rhs) {
(void)lhs;
(void)rhs;
PANIC("ubsan: divrem overflow: type=%s", data->type->name);
}

struct out_of_bounds_data {
struct source_location location;
const struct type_descriptor* array_type;
const struct type_descriptor* index_type;
};

void __ubsan_handle_out_of_bounds(const struct out_of_bounds_data* data,
const void* index) {
(void)index;
PANIC("ubsan: out of bounds: array=%s index=%s", data->array_type->name,
data->index_type->name);
}

struct type_mismatch_data {
struct source_location location;
const struct type_descriptor* type;
uint8_t log_alignment;
uint8_t type_check_kind;
};

void __ubsan_handle_type_mismatch_v1(const struct type_mismatch_data* data,
const void* ptr) {
unsigned alignment = 1U << data->log_alignment;
bool aligned = ((uintptr_t)ptr & (alignment - 1)) == 0;
PANIC("ubsan: type mismatch: ptr=%p type=%s kind=%u alignment=%u (%s)\n",
ptr, data->type->name, data->type_check_kind, alignment,
aligned ? "aligned" : "misaligned");
}

struct unreachable_data {
struct source_location location;
};

void __ubsan_handle_builtin_unreachable(const struct unreachable_data* data) {
(void)data;
PANIC("ubsan: builtin unreachable");
}

struct invalid_builtin_data {
struct source_location location;
uint8_t kind;
};

void __ubsan_handle_invalid_builtin(const struct invalid_builtin_data* data) {
PANIC("ubsan: invalid builtin: kind=%u", data->kind);
}

struct pointer_overflow_data {
struct source_location location;
};

void __ubsan_handle_pointer_overflow(const struct pointer_overflow_data* data,
const void* base, const void* result) {
(void)data;
PANIC("ubsan: pointer overflow: base=%p result=%p", base, result);
}
3 changes: 2 additions & 1 deletion kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ OBJS := \
../common/string.o \
../common/strings.o \
../common/stdio.o \
../common/stdlib.o
../common/stdlib.o \
../common/ubsan.o

DEPS := $(OBJS:.o=.d)

Expand Down
10 changes: 1 addition & 9 deletions kernel/panic.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
#pragma once

#include "api/err.h"
#include <common/extra.h>
#include <stddef.h>
#include <stdnoreturn.h>
#include <common/panic.h>

#define PANIC(...) panic(__FILE__, __LINE__, __VA_ARGS__)
#define UNREACHABLE() PANIC("Unreachable")
#define UNIMPLEMENTED() PANIC("Unimplemented")
#define ASSERT(cond) ((cond) ? (void)0 : PANIC("Assertion failed: " #cond))
#define ASSERT_OK(result) ASSERT(IS_OK(result))

noreturn void panic(const char* file, size_t line, const char* message, ...);
4 changes: 3 additions & 1 deletion kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ int time_now(clockid_t clock_id, struct timespec* tp) {
case CLOCK_MONOTONIC: {
unsigned t = uptime;
tp->tv_sec = t / CLK_TCK;
tp->tv_nsec = (t - tp->tv_sec * CLK_TCK) * NANOS / CLK_TCK;
tp->tv_nsec =
divmodi64(((uint64_t)t - (uint64_t)tp->tv_sec * CLK_TCK) * NANOS,
CLK_TCK, NULL);
break;
}
default:
Expand Down
1 change: 1 addition & 0 deletions userland/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ LIB_OBJS := \
../common/strings.o \
../common/stdio.o \
../common/stdlib.o \
../common/ubsan.o \
lib/asm.o \
lib/crt0.o \
lib/dirent.o \
Expand Down
9 changes: 1 addition & 8 deletions userland/lib/panic.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
#pragma once

#include <stddef.h>
#include <stdnoreturn.h>
#include <common/panic.h>

#define PANIC(...) panic(__FILE__, __LINE__, __VA_ARGS__)
#define UNREACHABLE() PANIC("Unreachable")
#define UNIMPLEMENTED() PANIC("Unimplemented")
#define ASSERT(cond) ((cond) ? (void)0 : PANIC("Assertion failed: " #cond))
#define ASSERT_OK(result) ASSERT((result) >= 0)
#define ASSERT_ERR(result) ASSERT((result) < 0)

noreturn void panic(const char* file, size_t line, const char* message, ...);

0 comments on commit dd6ef72

Please sign in to comment.