[PATCH] lib : sbi: UBSan implementation for OpenSBI

Marcos Oduardo marcos.oduardo at gmail.com
Wed Jan 14 03:49:06 PST 2026


UBSan (Undefined Behaviour Sanitizer) is a tool implemented using
compiler instrumentation at runtime that allows checking for statements
whose output is not deterministic or defined by the C standard,
incurring unexpected results in the execution of the program. Compiling
and testing the OpenSBI firmware against UBSan will print a message in
the console if any sentence performs any of these actions.

Support for this implementation involves two main components:
1.- The UBSan implementation hooks, used by the compiler to handle the
    check output
2.- A test suite to verify correct operation at runtime

Usage:

Users may compile OpenSBI with the UBSan instrumentation adding the
next flag to the make command:
ENABLEUBSAN=y

Users may compile OpenSBI with the UBSan tests adding the next flag to
the make command:
ENABLEUBSANTESTS=y

Note that the implementation of UBSan in the compilation of OpenSBI
adds a certain overhead caused by the checks performed at runtime;
therefore, it is only expected to be used in development builds, never
in production. If ENABLEUBSAN is not set, tests won't be compiled even
if the ENABLEUBSANTESTS flag is enabled.

Signed-off-by: Marcos Oduardo <marcos.oduardo at gmail.com>
---
 Makefile                     |  14 ++
 include/sbi/sbi_ubsan.h      | 182 ++++++++++++++++++
 include/sbi/sbi_ubsan_test.h |  28 +++
 lib/sbi/objects.mk           |   2 +
 lib/sbi/sbi_init.c           |  15 ++
 lib/sbi/sbi_ubsan.c          | 344 +++++++++++++++++++++++++++++++++++
 lib/sbi/sbi_ubsan_test.c     | 135 ++++++++++++++
 7 files changed, 720 insertions(+)
 create mode 100644 include/sbi/sbi_ubsan.h
 create mode 100644 include/sbi/sbi_ubsan_test.h
 create mode 100644 lib/sbi/sbi_ubsan.c
 create mode 100644 lib/sbi/sbi_ubsan_test.c

diff --git a/Makefile b/Makefile
index 46541063..200130e3 100644
--- a/Makefile
+++ b/Makefile
@@ -455,6 +455,20 @@ else
 CFLAGS		+=	-O2
 endif
 
+ifeq ($(ENABLEUBSAN),y) 
+#UBsan-specific compiler options
+KUBSAN_CC_FLAGS := -fsanitize=undefined
+KUBSAN_CC_FLAGS += -fno-sanitize=pointer-overflow #unimplemented handler
+KUBSAN_CC_FLAGS += -fsanitize=implicit-signed-integer-truncation
+KUBSAN_CC_FLAGS += -fno-sanitize=function #unimplemented handler
+KUBSAN_CC_FLAGS += -fno-sanitize-link-runtime
+KUBSAN_CC_FLAGS += -DUBSAN_ENABLED
+ifeq ($(ENABLEUBSANTESTS),y) 
+KUBSAN_CC_FLAGS += -DUBSAN_TESTS_ENABLED
+endif
+CFLAGS += $(KUBSAN_CC_FLAGS)
+endif
+
 ifeq ($(V), 1)
 ELFFLAGS	+=	-Wl,--print-gc-sections
 endif
diff --git a/include/sbi/sbi_ubsan.h b/include/sbi/sbi_ubsan.h
new file mode 100644
index 00000000..7ecd17ec
--- /dev/null
+++ b/include/sbi/sbi_ubsan.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LIB_UBSAN_H
+#define _LIB_UBSAN_H
+
+#include <sbi/sbi_types.h>
+
+
+
+#ifndef INT_MIN
+#define INT_MIN          (-__INT_MAX__ - 1)
+#endif
+#ifndef INT_MAX
+#define INT_MAX          __INT_MAX__
+#endif
+
+#ifndef LONG_MIN
+#define LONG_MIN         (-__LONG_MAX__ - 1)
+#endif
+#ifndef LONG_MAX
+#define LONG_MAX         __LONG_MAX__
+#endif
+
+/*
+ * ABI defined by Clang's UBSAN enum SanitizerHandler:
+ * https://github.com/llvm/llvm-project/blob/release/16.x/clang/lib/CodeGen/CodeGenFunction.h#L113
+ */
+enum ubsan_checks {
+	ubsan_add_overflow,
+	ubsan_builtin_unreachable,
+	ubsan_cfi_check_fail,
+	ubsan_divrem_overflow,
+	ubsan_dynamic_type_cache_miss,
+	ubsan_float_cast_overflow,
+	ubsan_function_type_mismatch,
+	ubsan_implicit_conversion,
+	ubsan_invalid_builtin,
+	ubsan_invalid_objc_cast,
+	ubsan_load_invalid_value,
+	ubsan_missing_return,
+	ubsan_mul_overflow,
+	ubsan_negate_overflow,
+	ubsan_nullability_arg,
+	ubsan_nullability_return,
+	ubsan_nonnull_arg,
+	ubsan_nonnull_return,
+	ubsan_out_of_bounds,
+	ubsan_pointer_overflow,
+	ubsan_shift_out_of_bounds,
+	ubsan_sub_overflow,
+	ubsan_type_mismatch,
+	ubsan_alignment_assumption,
+	ubsan_vla_bound_not_positive,
+};
+
+enum {
+	type_kind_int = 0,
+	type_kind_float = 1,
+	type_unknown = 0xffff
+};
+
+struct type_descriptor {
+	u16 type_kind;
+	u16 type_info;
+	char type_name[];
+};
+
+struct source_location {
+	const char *file_name;
+	union {
+		unsigned long reported;
+		struct {
+			u32 line;
+			u32 column;
+		};
+	};
+};
+
+struct overflow_data {
+	struct source_location location;
+	struct type_descriptor *type;
+};
+
+struct implicit_conversion_data {
+	struct source_location location;
+	struct type_descriptor *from_type;
+	struct type_descriptor *to_type;
+	unsigned char type_check_kind;
+};
+
+struct type_mismatch_data {
+	struct source_location location;
+	struct type_descriptor *type;
+	unsigned long alignment;
+	unsigned char type_check_kind;
+};
+
+struct type_mismatch_data_v1 {
+	struct source_location location;
+	struct type_descriptor *type;
+	unsigned char log_alignment;
+	unsigned char type_check_kind;
+};
+
+struct type_mismatch_data_common {
+	struct source_location *location;
+	struct type_descriptor *type;
+	unsigned long alignment;
+	unsigned char type_check_kind;
+};
+
+struct nonnull_arg_data {
+	struct source_location location;
+	struct source_location attr_location;
+	int arg_index;
+};
+
+struct out_of_bounds_data {
+	struct source_location location;
+	struct type_descriptor *array_type;
+	struct type_descriptor *index_type;
+};
+
+struct shift_out_of_bounds_data {
+	struct source_location location;
+	struct type_descriptor *lhs_type;
+	struct type_descriptor *rhs_type;
+};
+
+struct unreachable_data {
+	struct source_location location;
+};
+
+struct invalid_value_data {
+	struct source_location location;
+	struct type_descriptor *type;
+};
+
+struct alignment_assumption_data {
+	struct source_location location;
+	struct source_location assumption_location;
+	struct type_descriptor *type;
+};
+
+
+#if defined(CONFIG_ARCH_SUPPORTS_INT128)
+typedef __int128 s_max;
+typedef unsigned __int128 u_max;
+#else
+typedef s64 s_max;
+typedef u64 u_max;
+#endif
+
+/*
+ * When generating Runtime Calls, Clang doesn't respect the -mregparm=3
+ * option used on i386: https://github.com/llvm/llvm-project/issues/89670
+ * Fix this for earlier Clang versions by forcing the calling convention
+ * to use non-register arguments.
+ */
+#if defined(CONFIG_X86_32) && \
+    defined(CONFIG_CC_IS_CLANG) && CONFIG_CLANG_VERSION < 190000
+# define ubsan_linkage asmlinkage
+#else
+# define ubsan_linkage
+#endif
+
+void ubsan_linkage __ubsan_handle_add_overflow(void *data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_sub_overflow(void *data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_mul_overflow(void *data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_negate_overflow(void *_data, void *old_val);
+void ubsan_linkage __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_implicit_conversion(void *_data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_type_mismatch(struct type_mismatch_data *data, void *ptr);
+void ubsan_linkage __ubsan_handle_type_mismatch_v1(void *_data, void *ptr);
+void ubsan_linkage __ubsan_handle_out_of_bounds(void *_data, void *index);
+void ubsan_linkage __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs);
+void ubsan_linkage __ubsan_handle_builtin_unreachable(void *_data);
+void ubsan_linkage __ubsan_handle_load_invalid_value(void *_data, void *val);
+void ubsan_linkage __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
+						       unsigned long align,
+						       unsigned long offset);
+
+#endif
\ No newline at end of file
diff --git a/include/sbi/sbi_ubsan_test.h b/include/sbi/sbi_ubsan_test.h
new file mode 100644
index 00000000..7ce8b7ba
--- /dev/null
+++ b/include/sbi/sbi_ubsan_test.h
@@ -0,0 +1,28 @@
+#ifndef __SBI_UBSAN_TEST_H__
+#define __SBI_UBSAN_TEST_H__
+
+#ifdef UBSAN_TESTS_ENABLED
+
+#include <sbi/sbi_ubsan.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_heap.h>
+
+void test_ubsan_add_overflow(void);
+void test_ubsan_sub_overflow(void);
+void test_ubsan_mul_overflow(void);
+void test_ubsan_negate_overflow(void);
+void test_ubsan_divrem_overflow(void);
+void test_ubsan_truncate_signed(void);
+void test_ubsan_shift_out_of_bounds(void);
+void test_ubsan_out_of_bounds(void);
+
+enum ubsan_test_enum {
+	UBSAN_TEST_ZERO = 0,
+	UBSAN_TEST_ONE,
+	UBSAN_TEST_MAX,
+};
+
+void test_ubsan_load_invalid_value(void);
+#endif
+#endif
\ No newline at end of file
diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk
index 07d13229..837d861e 100644
--- a/lib/sbi/objects.mk
+++ b/lib/sbi/objects.mk
@@ -64,6 +64,8 @@ libsbi-objs-$(CONFIG_SBI_ECALL_SSE) += sbi_ecall_sse.o
 carray-sbi_ecall_exts-$(CONFIG_SBI_ECALL_MPXY) += ecall_mpxy
 libsbi-objs-$(CONFIG_SBI_ECALL_MPXY) += sbi_ecall_mpxy.o
 
+libsbi-objs-y += sbi_ubsan.o
+libsbi-objs-y += sbi_ubsan_test.o
 libsbi-objs-y += sbi_bitmap.o
 libsbi-objs-y += sbi_bitops.o
 libsbi-objs-y += sbi_console.o
diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c
index 5259064b..dcf96d20 100644
--- a/lib/sbi/sbi_init.c
+++ b/lib/sbi/sbi_init.c
@@ -35,6 +35,8 @@
 #include <sbi/sbi_tlb.h>
 #include <sbi/sbi_version.h>
 #include <sbi/sbi_unit_test.h>
+#include <sbi/sbi_ubsan.h>
+#include <sbi/sbi_ubsan_test.h>
 
 #define BANNER                                              \
 	"   ____                    _____ ____ _____\n"     \
@@ -288,6 +290,19 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid)
 
 	sbi_double_trap_init(scratch);
 
+	#ifdef UBSAN_TESTS_ENABLED
+
+    test_ubsan_add_overflow();
+	test_ubsan_sub_overflow();
+	test_ubsan_mul_overflow();
+	test_ubsan_negate_overflow();
+    test_ubsan_divrem_overflow();
+	test_ubsan_truncate_signed();
+	test_ubsan_shift_out_of_bounds();
+	test_ubsan_out_of_bounds();
+	
+	#endif
+	
 	rc = sbi_irqchip_init(scratch, true);
 	if (rc) {
 		sbi_printf("%s: irqchip init failed (error %d)\n",
diff --git a/lib/sbi/sbi_ubsan.c b/lib/sbi/sbi_ubsan.c
new file mode 100644
index 00000000..1118203c
--- /dev/null
+++ b/lib/sbi/sbi_ubsan.c
@@ -0,0 +1,344 @@
+#include <sbi/sbi_string.h>
+#include <sbi/sbi_console.h>
+#include <sbi/sbi_ubsan.h>
+
+#define REPORTED_BIT 31
+
+#if (BITS_PER_LONG == 64) && defined(__BIG_ENDIAN)
+#define COLUMN_MASK (~(1U << REPORTED_BIT))
+#define LINE_MASK   (~0U)
+#else
+#define COLUMN_MASK   (~0U)
+#define LINE_MASK (~(1U << REPORTED_BIT))
+#endif
+
+#define VALUE_LENGTH 40
+#define IS_ALIGNED(x, a)        (((x) & ((typeof(x))(a) - 1)) == 0)
+#define BIT(nr) (1UL << (nr))
+#define __attribute_const__             __attribute__((__const__))
+
+#define ffs(x) __builtin_ffs(x)
+
+typedef long ssize_t;
+
+static const char * const type_check_kinds[] = {
+	"load of",
+	"store to",
+	"reference binding to",
+	"member access within",
+	"member call on",
+	"constructor call on",
+	"downcast of",
+	"downcast of"
+};
+
+
+static bool type_is_signed(struct type_descriptor *type)
+{
+	return  type->type_info & 1;
+}
+
+static unsigned type_bit_width(struct type_descriptor *type)
+{
+	return 1 << (type->type_info >> 1);
+}
+
+static bool is_inline_int(struct type_descriptor *type)
+{
+	unsigned inline_bits = sizeof(unsigned long)*8;
+	unsigned bits = type_bit_width(type);
+
+	return bits <= inline_bits;
+}
+
+static s_max get_signed_val(struct type_descriptor *type, void *val)
+{
+	if (is_inline_int(type)) {
+		unsigned extra_bits = sizeof(s_max)*8 - type_bit_width(type);
+		unsigned long ulong_val = (unsigned long)val;
+
+		return ((s_max)ulong_val) << extra_bits >> extra_bits;
+	}
+
+	if (type_bit_width(type) == 64)
+		return *(s64 *)val;
+
+	return *(s_max *)val;
+}
+
+static bool val_is_negative(struct type_descriptor *type, void *val)
+{
+	return type_is_signed(type) && get_signed_val(type, val) < 0;
+}
+
+static u_max get_unsigned_val(struct type_descriptor *type, void *val)
+{
+	if (is_inline_int(type))
+		return (unsigned long)val;
+
+	if (type_bit_width(type) == 64)
+		return *(u64 *)val;
+
+	return *(u_max *)val;
+}
+
+
+static void ubsan_prologue(struct source_location *loc, const char *reason)
+{
+
+	sbi_printf("================================================================================\n");//pr_warn(CUT_HERE);
+
+	sbi_printf("UBSAN: %s in %s:%d:%d\n", reason, loc->file_name,
+		loc->line & LINE_MASK, loc->column & COLUMN_MASK); 
+}
+
+static void ubsan_epilogue(void)
+{
+	sbi_printf("----------------------\n");
+}
+
+static void handle_overflow(struct overflow_data *data, void *lhs,
+			void *rhs, char op)
+{
+
+	struct type_descriptor *type = data->type;
+
+	ubsan_prologue(&data->location, type_is_signed(type) ?
+			"signed-integer-overflow" :
+			"unsigned-integer-overflow");
+	
+    sbi_printf("%c operation cannot be represented in type %s with those operands\n",
+		op,
+		type->type_name);
+    
+
+	ubsan_epilogue();
+}
+
+
+void __ubsan_handle_add_overflow(void *data,
+				void *lhs, void *rhs)
+{
+
+	handle_overflow(data, lhs, rhs, '+');
+}
+
+
+void __ubsan_handle_sub_overflow(void *data,
+				void *lhs, void *rhs)
+{
+	handle_overflow(data, lhs, rhs, '-');
+}
+
+void __ubsan_handle_mul_overflow(void *data,
+				void *lhs, void *rhs)
+{
+	handle_overflow(data, lhs, rhs, '*');
+}
+
+void __ubsan_handle_negate_overflow(void *_data, void *old_val)
+{
+	struct overflow_data *data = _data;
+
+	ubsan_prologue(&data->location, "negation-overflow");
+
+    sbi_printf("negation of this value cannot be represented in type %s\n",
+    data->type->type_name);
+
+	ubsan_epilogue();
+}
+
+void __ubsan_handle_implicit_conversion(void *_data, void *from_val, void *to_val)
+{
+	struct implicit_conversion_data *data = _data;
+	char from_val_str[VALUE_LENGTH];
+
+	ubsan_prologue(&data->location, "implicit-conversion");
+    	
+    sbi_printf("cannot represent %s value %s during %s %s: truncated.\n",
+        data->from_type->type_name,
+        from_val_str,
+        type_check_kinds[data->type_check_kind],
+        data->to_type->type_name);
+    
+
+	ubsan_epilogue();
+}
+
+
+void __ubsan_handle_divrem_overflow(void *_data, void *lhs, void *rhs)
+{
+	struct overflow_data *data = _data;
+
+	ubsan_prologue(&data->location, "division-overflow");
+
+	if (type_is_signed(data->type) && get_signed_val(data->type, rhs) == -1)
+		sbi_printf("division of this value by -1 cannot be represented in type %s\n",
+			 data->type->type_name);
+	else
+		sbi_printf("division by zero\n");
+
+     
+
+	ubsan_epilogue();
+}
+
+static void handle_null_ptr_deref(struct type_mismatch_data_common *data)
+{
+
+	ubsan_prologue(data->location, "null-ptr-deref");
+
+	sbi_printf("%s null pointer of type %s\n",
+		type_check_kinds[data->type_check_kind],
+		data->type->type_name);
+
+	ubsan_epilogue();
+}
+
+static void handle_misaligned_access(struct type_mismatch_data_common *data,
+				unsigned long ptr)
+{
+
+	ubsan_prologue(data->location, "misaligned-access");
+
+	sbi_printf("%s misaligned address %p for type %s\n",
+		type_check_kinds[data->type_check_kind],
+		(void *)ptr, data->type->type_name);
+	sbi_printf("which requires %ld byte alignment\n", data->alignment);
+
+	ubsan_epilogue();
+}
+
+static void handle_object_size_mismatch(struct type_mismatch_data_common *data,
+					unsigned long ptr)
+{
+
+	ubsan_prologue(data->location, "object-size-mismatch");
+	sbi_printf("%s address %p with insufficient space\n",
+		type_check_kinds[data->type_check_kind],
+		(void *) ptr);
+	sbi_printf("for an object of type %s\n", data->type->type_name);
+	ubsan_epilogue();
+}
+
+static void ubsan_type_mismatch_common(struct type_mismatch_data_common *data,
+				unsigned long ptr)
+{
+
+	if (!ptr)
+		handle_null_ptr_deref(data);
+	else if (data->alignment && !IS_ALIGNED(ptr, data->alignment))
+		handle_misaligned_access(data, ptr);
+	else
+		handle_object_size_mismatch(data, ptr);
+
+}
+
+void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
+				void *ptr)
+{
+	struct type_mismatch_data_common common_data = {
+		.location = &data->location,
+		.type = data->type,
+		.alignment = data->alignment,
+		.type_check_kind = data->type_check_kind
+	};
+
+	ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
+}
+
+void __ubsan_handle_type_mismatch_v1(void *_data, void *ptr)
+{
+	struct type_mismatch_data_v1 *data = _data;
+	struct type_mismatch_data_common common_data = {
+		.location = &data->location,
+		.type = data->type,
+		.alignment = 1UL << data->log_alignment,
+		.type_check_kind = data->type_check_kind
+	};
+
+	ubsan_type_mismatch_common(&common_data, (unsigned long)ptr);
+}
+
+void __ubsan_handle_out_of_bounds(void *_data, void *index)
+{
+	struct out_of_bounds_data *data = _data;
+
+	ubsan_prologue(&data->location, "array-index-out-of-bounds");
+
+    sbi_printf("used index is out of range for type %s\n",
+		data->array_type->type_name);
+	ubsan_epilogue();
+
+
+}
+
+void __ubsan_handle_shift_out_of_bounds(void *_data, void *lhs, void *rhs)
+{
+	struct shift_out_of_bounds_data *data = _data;
+	struct type_descriptor *rhs_type = data->rhs_type;
+	struct type_descriptor *lhs_type = data->lhs_type;
+
+	ubsan_prologue(&data->location, "shift-out-of-bounds");
+
+    if (val_is_negative(rhs_type, rhs))
+    sbi_printf("shift exponent is negative\n");
+
+	else if (get_unsigned_val(rhs_type, rhs) >=
+		type_bit_width(lhs_type))
+		sbi_printf("shift exponent is too large for %u-bit type %s\n",
+			type_bit_width(lhs_type),
+			lhs_type->type_name);
+	else if (val_is_negative(lhs_type, lhs))
+		sbi_printf("left shift of negative value\n");
+	else
+		sbi_printf("left shift of this value by this places cannot be"
+			" represented in type %s\n", lhs_type->type_name);
+
+	ubsan_epilogue();
+
+}
+
+void __ubsan_handle_builtin_unreachable(void *_data)
+{
+	struct unreachable_data *data = _data;
+	ubsan_prologue(&data->location, "unreachable");
+	sbi_printf("calling __builtin_unreachable()\n");
+	ubsan_epilogue();
+}
+
+void __ubsan_handle_load_invalid_value(void *_data, void *val)
+{
+	struct invalid_value_data *data = _data;
+
+	ubsan_prologue(&data->location, "invalid-load");
+
+   	sbi_printf("load of this value is not a valid value for type %s\n", data->type->type_name);
+
+	ubsan_epilogue();
+
+}
+
+void __ubsan_handle_alignment_assumption(void *_data, unsigned long ptr,
+					 unsigned long align,
+					 unsigned long offset)
+{
+	struct alignment_assumption_data *data = _data;
+	unsigned long real_ptr;
+
+	ubsan_prologue(&data->location, "alignment-assumption");
+
+	if (offset)
+		sbi_printf("assumption of %lu byte alignment (with offset of %lu byte) for pointer of type %s failed",
+		       align, offset, data->type->type_name);
+	else
+		sbi_printf("assumption of %lu byte alignment for pointer of type %s failed",
+		       align, data->type->type_name);
+
+	real_ptr = ptr - offset;
+	sbi_printf("%saddress is %lu aligned, misalignment offset is %lu bytes",
+	       offset ? "offset " : "", BIT(real_ptr ? ffs(real_ptr) : 0),
+	       real_ptr & (align - 1));
+
+	ubsan_epilogue();
+}
\ No newline at end of file
diff --git a/lib/sbi/sbi_ubsan_test.c b/lib/sbi/sbi_ubsan_test.c
new file mode 100644
index 00000000..35d16930
--- /dev/null
+++ b/lib/sbi/sbi_ubsan_test.c
@@ -0,0 +1,135 @@
+#ifdef UBSAN_TESTS_ENABLED
+#include <sbi/sbi_ubsan_test.h>
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#pragma GCC diagnostic ignored "-Wpointer-sign"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wunused-function"
+
+
+void test_ubsan_add_overflow(void)
+{
+	volatile int val = INT_MAX;
+  sbi_printf("\nKUBSan test: integer overflow in add operation\n");
+  sbi_printf("Overflowing integer variable with INT_MAX value\n");
+  
+	val += 2;
+}
+
+void test_ubsan_sub_overflow(void)
+{
+	volatile int val = INT_MIN;
+	volatile int val2 = 2;
+
+  sbi_printf("\nKUBSan test: integer underflow in sub operation\n");
+  sbi_printf("Underflowing integer variable with INT_MIN value\n");
+
+	val -= val2;
+
+}
+
+void test_ubsan_mul_overflow(void)
+{
+	volatile int val = INT_MAX / 2;
+
+  
+  sbi_printf("\nKUBSan test: integer overflow in mul operation\n");
+  sbi_printf("Overflowing integer variable with INT_MAX value\n");
+
+	val *= 3;
+}
+
+void test_ubsan_negate_overflow(void)
+{
+	volatile int val = INT_MIN;
+
+  sbi_printf("\nKUBSan test: integer negate overflow\n");
+  sbi_printf("Overflowing by negating integer variable with INT_MIN value\n");
+
+	val = -val;
+}
+
+void test_ubsan_divrem_overflow(void)
+{
+	volatile int val = 16;
+	volatile int val2 = 0;
+
+  sbi_printf("\nKUBSan test: integer division by zero\n");
+  sbi_printf("Dividing by zero variable with %d value\n", val);
+
+	val /= val2;
+}
+
+void test_ubsan_truncate_signed(void)
+{
+	volatile long val = LONG_MAX;
+	volatile int val2 = 0;
+
+  sbi_printf("\nKUBSan test: signed variable truncation\n");
+  sbi_printf("Truncating long variable with LONG_MAX value assigning its value to a int variable\n");
+
+	val2 = val;
+
+  
+}
+
+void test_ubsan_shift_out_of_bounds(void)
+{
+	volatile int neg = -1, wrap = 4;
+	volatile int val1 = 10;
+	volatile int val2 = INT_MAX;
+
+  sbi_printf("\nKUBSan test: OOB shift\n");
+  sbi_printf("Performing negative exponent right shift and left overflow shift in INT_MAX variable\n");
+
+	val1 <<= neg;
+
+	val2 <<= wrap;
+}
+
+
+void test_ubsan_out_of_bounds(void)
+{
+	int i = 4, j = 4, k = -1;
+	volatile struct {
+		char above[4]; /* Protect surrounding memory. */
+		int arr[4];
+		char below[4]; /* Protect surrounding memory. */
+	} data;
+
+  sbi_printf("\nKUBSan test: OOB write\n");
+  sbi_printf("Attempting to write data in OOB space of a %d positions array\n", i);
+
+	data.arr[j] = i;
+
+	data.arr[k] = i;
+}
+
+void test_ubsan_load_invalid_value(void)
+{
+	volatile char *dst, *src;
+	bool val, val2, *ptr;
+	enum ubsan_test_enum eval, eval2, *eptr;
+	unsigned char c = 0xff;
+
+  sbi_printf("\nKUBSan test: Invalid load value\n");
+  sbi_printf("Attempting to load a value with wrong type pointers\n");
+
+	dst = (char *)&val;
+	src = &c;
+	*dst = *src;
+
+	ptr = &val2;
+	val2 = val;
+
+	dst = (char *)&eval;
+	src = &c;
+	*dst = *src;
+
+	eptr = &eval2;
+	eval2 = eval;
+}
+
+#pragma GCC diagnostic pop
+#endif
\ No newline at end of file
-- 
2.43.0




More information about the opensbi mailing list