From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A39CBC636C1 for ; Sun, 22 Feb 2026 22:45:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=NslROC2P9c0c3sgiN5p2GYm3hnq6AM8aGSlESSrnGvY=; b=IamvaJEFmP2go7 B0nu5f89vvLhfKeUupxMtp7rHf1UhFxjeLsCPc9WJbeE29L3ztoYhAJj1Fn3YQgDbrnbOkFceVsMb XAVaIRSYbpF2NY5xyVfGtQqf+sIkMo79IlAggBAHwGUMzrPFm9WywTaVVy7OUnUmaJisMVz6TNv2k j86JpCBENBaF4F8vMuRjac26uD/QAuzNeD23doqzFj6+LHIW/k/kpYdqLFNekQdVleUvVakoUOVN0 9Tsw31of54wJii+U51+//w1s5tjPW15k+5z+XdPK8BzwtJ0krravI+AepHPEdlZBx+SI4NrNMtTDu 2DeN6FKnLQNFYCd5o+pA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98.2 #2 (Red Hat Linux)) id 1vuICD-0000000H1cR-3oDk; Sun, 22 Feb 2026 22:45:01 +0000 Received: from mail-wm1-x32c.google.com ([2a00:1450:4864:20::32c]) by bombadil.infradead.org with esmtps (Exim 4.98.2 #2 (Red Hat Linux)) id 1vuICA-0000000H1bk-1RDk for opensbi@lists.infradead.org; Sun, 22 Feb 2026 22:45:00 +0000 Received: by mail-wm1-x32c.google.com with SMTP id 5b1f17b1804b1-4806f3fc50bso42394715e9.0 for ; Sun, 22 Feb 2026 14:44:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1771800296; x=1772405096; darn=lists.infradead.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=8y7txO08xf8IITVibF+/9NGjslRPgoD5pYMCQRjtkQ8=; b=k3ndn6vLh5/Mn/MuOVMwhd+5EC1CdZg0KOwdpYnHFSUvZ17ep7Y0qYgsk/deqO3/nJ Zs0BSggyd5Qa9+IwdjWwP7l2AS8NnGKTW04f2pzHxgGS+tiMduCGr/sbHNj/tKFpsj0z HC/43+r2ihNG9vnf6PU5Jx9Yw4LeXMMCX6a2tLoHHIJCmnuT5so8IID7DsKIY7KnlPwl lfg1taHx+PRy36tMDVF72exsvN9V7YN+mm3zxbzRncYnJHTmNiInIc3sn9+wQZO4KjFz qcMrOkofoufaBgcfdvhiee3+NBOprFqXecEFmJge3KQKxsQhzN2P/UytOQEybOf7Auew KmOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771800296; x=1772405096; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=8y7txO08xf8IITVibF+/9NGjslRPgoD5pYMCQRjtkQ8=; b=hI0TB2EUcUMo8pTYZoSJCsc5858YUCpg6apb2d09bd19eYe1B/atV7RmbDMiw8u2e5 3lbZw/w0Cd+/onz5Sbc8+HSOqMxSgmpQSNmQ8RWJluCU9t7IV4pPEteT9vY9IeijFWRu cCMjwCrVPMMSoC/peaymhArRvricCIY1RwBZ9JN0tTG4BgkXxh79AQIFsgqQ6o+L9LSA 9fiUcuV+raKC7TxcuKRvXYJVCHNFaJ9WqHBSiyp+YIj+2u/8DFTvSAdE0G8cchH6iQmd qlAEanavWGMSN0rVWMXDS58LUQ/bnVIgnRQn6wbH76s/e/HkJM7x2dhOhjCcgavvZVOn 3Ijg== X-Gm-Message-State: AOJu0Yw+3rWMWL332+u2Z1PO5eJGQfOFiHUUaRZbPu+5GH/+S/Ab1zGI s50QzCm8/wono2VZ05Uk0ns3OI0iJPBQ6zCBsuGHmuVrgkO3hn84IBHxyr767w== X-Gm-Gg: AZuq6aJytS2BZM2x39vdMeCeEVEHv8eXeMMHCwIYDrPTqAhwdvERdynDFCMq3HgKQk5 6IFaWm/HZROLy+OUhFRC/4ZglYleH9wIosE5SR1Lu+snZaJovA71XvOBm1lOUsZ6LwK3ByQ0FcB pVtFuRd2F7EoXr+gLp4BSH1D1yMP7AE+HBdyF3tgPneJCICT1d4J6CnuM6JzNX1uDWjpd27YzVc ZD1Ggn3ClgSIR7SBlCJtLxNiaBp5WepQuQJrxGDEZvN1R+DXVWW5HUXIepghiMFWsrWGrOhi/GM iDkU2ML2PPQybJOYgw/A5ofOUYEUBx6JsW4kBcZJsbl9TM4m1mdbWx8OqkWj09SG3VOpZXCEp9y pkRA5euJtWVD0hLjppLIzxHnmXoxdcCVVCuCgJ8NYOQORcAMzIrDJKF2rIMCe8vet+2A41qTxfQ aNDYTbmL0BCctSxS9sDCvl6aSFMQrMZdwIBr2pqBq6vJ//Vm5Y4RzPLmPTTDJbf0UTGkDcAdIsa PbwQwcptC7CHjaHvs3NKgBiLG9XA+BWs5wVjQEIacnFo98kmJ/XQ4/ND1myLSESsA== X-Received: by 2002:a05:600c:5020:b0:477:5cc6:7e44 with SMTP id 5b1f17b1804b1-483a95fb698mr125248805e9.11.1771800295767; Sun, 22 Feb 2026 14:44:55 -0800 (PST) Received: from marcosthinkpad ([79.116.216.227]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-483a42eb8acsm72380295e9.12.2026.02.22.14.44.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 22 Feb 2026 14:44:54 -0800 (PST) From: Marcos Oduardo To: opensbi@lists.infradead.org Cc: Marcos Oduardo Subject: [PATCH v3] lib: sbi: add UBSan support Date: Sun, 22 Feb 2026 23:45:42 +0100 Message-ID: <20260222224542.239942-1-marcos.oduardo@gmail.com> X-Mailer: git-send-email 2.53.0 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20260222_144458_641616_EB84F4F2 X-CRM114-Status: GOOD ( 23.18 ) X-BeenThere: opensbi@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "opensbi" Errors-To: opensbi-bounces+opensbi=archiver.kernel.org@lists.infradead.org UBSan (Undefined Behavior 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 (derived from NetBSD), 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 --- Changes since v2: - Fixed packaging error that included the patch file itself in the commit. Makefile | 14 + include/sbi/sbi_ubsan_test.h | 8 + lib/sbi/objects.mk | 6 + lib/sbi/sbi_init.c | 6 + lib/sbi/sbi_ubsan.c | 849 +++++++++++++++++++++++++++++++++++ lib/sbi/sbi_ubsan_test.c | 147 ++++++ 6 files changed, 1030 insertions(+) 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..0689242b 100644 --- a/Makefile +++ b/Makefile @@ -455,6 +455,20 @@ else CFLAGS += -O2 endif +ifeq ($(ENABLEUBSAN),y) +UBSAN_CC_FLAGS := -fsanitize=undefined +UBSAN_CC_FLAGS += -DUBSAN_ENABLED +ifeq ($(ENABLEUBSANTESTS),y) +UBSAN_CC_FLAGS += -DUBSAN_TESTS_ENABLED +endif +UBSAN_CC_FLAGS += -fno-sanitize=vptr +UBSAN_CC_FLAGS += -fno-sanitize=float-cast-overflow +UBSAN_CC_FLAGS += -fno-sanitize=float-divide-by-zero +UBSAN_CC_FLAGS += -fsanitize-recover=undefined +UBSAN_CC_FLAGS += -fsanitize=pointer-overflow +CFLAGS += $(UBSAN_CC_FLAGS) +endif + ifeq ($(V), 1) ELFFLAGS += -Wl,--print-gc-sections endif diff --git a/include/sbi/sbi_ubsan_test.h b/include/sbi/sbi_ubsan_test.h new file mode 100644 index 00000000..13c6a562 --- /dev/null +++ b/include/sbi/sbi_ubsan_test.h @@ -0,0 +1,8 @@ +#ifdef UBSAN_TESTS_ENABLED +#ifndef __SBI_UBSAN_TEST_H__ +#define __SBI_UBSAN_TEST_H__ + +void sbi_ubsan_test_suite(void); + +#endif +#endif \ No newline at end of file diff --git a/lib/sbi/objects.mk b/lib/sbi/objects.mk index 07d13229..b6f97120 100644 --- a/lib/sbi/objects.mk +++ b/lib/sbi/objects.mk @@ -99,6 +99,12 @@ libsbi-objs-y += sbi_tlb.o libsbi-objs-y += sbi_trap.o libsbi-objs-y += sbi_trap_ldst.o libsbi-objs-y += sbi_trap_v_ldst.o +ifeq ($(ENABLEUBSAN), y) +libsbi-objs-y += sbi_ubsan.o +ifeq ($(ENABLEUBSANTESTS), y) +libsbi-objs-y += sbi_ubsan_test.o +endif +endif libsbi-objs-y += sbi_unpriv.o libsbi-objs-y += sbi_expected_trap.o libsbi-objs-y += sbi_cppc.o diff --git a/lib/sbi/sbi_init.c b/lib/sbi/sbi_init.c index 5259064b..5155716c 100644 --- a/lib/sbi/sbi_init.c +++ b/lib/sbi/sbi_init.c @@ -35,6 +35,8 @@ #include #include #include +#include + #define BANNER \ " ____ _____ ____ _____\n" \ @@ -288,6 +290,10 @@ static void __noreturn init_coldboot(struct sbi_scratch *scratch, u32 hartid) sbi_double_trap_init(scratch); + #ifdef UBSAN_TESTS_ENABLED + sbi_ubsan_test_suite(); + #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..f341275f --- /dev/null +++ b/lib/sbi/sbi_ubsan.c @@ -0,0 +1,849 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Author: Marcos Oduardo + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef UBSAN_ENABLED + +#include +#include + +/* Undefined Behavior specific defines and structures. Type descriptors defined by the compiler ABI */ + +#define KIND_INTEGER 0 +#define KIND_FLOAT 1 +#define KIND_UNKNOWN UINT16_MAX + +struct CSourceLocation { + char *mFilename; + uint32_t mLine; + uint32_t mColumn; +}; + +struct CTypeDescriptor { + uint16_t mTypeKind; + uint16_t mTypeInfo; + uint8_t mTypeName[1]; +}; + +struct COverflowData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CUnreachableData { + struct CSourceLocation mLocation; +}; + +struct CCFICheckFailData { + uint8_t mCheckKind; + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CDynamicTypeCacheMissData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + void *mTypeInfo; + uint8_t mTypeCheckKind; +}; + +struct CFunctionTypeMismatchData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CInvalidBuiltinData { + struct CSourceLocation mLocation; + uint8_t mKind; +}; + +struct CInvalidValueData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CNonNullArgData { + struct CSourceLocation mLocation; + struct CSourceLocation mAttributeLocation; + int mArgIndex; +}; + +struct CNonNullReturnData { + struct CSourceLocation mAttributeLocation; +}; + +struct COutOfBoundsData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mArrayType; + struct CTypeDescriptor *mIndexType; +}; + +struct CPointerOverflowData { + struct CSourceLocation mLocation; +}; + +struct CShiftOutOfBoundsData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mLHSType; + struct CTypeDescriptor *mRHSType; +}; + +struct CTypeMismatchData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + unsigned long mLogAlignment; + uint8_t mTypeCheckKind; +}; + +struct CTypeMismatchData_v1 { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; + uint8_t mLogAlignment; + uint8_t mTypeCheckKind; +}; + +struct CVLABoundData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mType; +}; + +struct CFloatCastOverflowData { + struct CSourceLocation mLocation; /* This field exists in this struct since 2015 August 11th */ + struct CTypeDescriptor *mFromType; + struct CTypeDescriptor *mToType; +}; + +struct CImplicitConversionData { + struct CSourceLocation mLocation; + struct CTypeDescriptor *mFromType; + struct CTypeDescriptor *mToType; + uint8_t mKind; +}; + +struct CAlignmentAssumptionData { + struct CSourceLocation mLocation; + struct CSourceLocation mAssumptionLocation; + struct CTypeDescriptor *mType; +}; + +/* Public symbols used in the instrumentation of the code generation part */ +void __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_alignment_assumption(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset); +void __ubsan_handle_alignment_assumption_abort(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset); +void __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData); +void __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +void __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +void __ubsan_handle_function_type_mismatch_v1(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI); +void __ubsan_handle_function_type_mismatch_v1_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction, unsigned long ulCalleeRTTI, unsigned long ulFnRTTI); +void __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData); +void __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData); +void __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulVal); +void __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulVal); +void __ubsan_handle_missing_return(struct CUnreachableData *pData); +void __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldVal); +void __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldVal); +void __ubsan_handle_nullability_arg(struct CNonNullArgData *pData); +void __ubsan_handle_nullability_arg_abort(struct CNonNullArgData *pData); +void __ubsan_handle_nullability_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_nullability_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex); +void __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex); +void __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); +void __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); +void __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS); +void __ubsan_handle_type_mismatch(struct CTypeMismatchData *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_abort(struct CTypeMismatchData *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer); +void __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer); +void __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound); +void __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound); +void __ubsan_get_current_report_data(const char **ppOutIssueKind, const char **ppOutMessage, const char **ppOutFilename, uint32_t *pOutLine, uint32_t *pOutCol, char **ppOutMemoryAddr); + +#if 0 +Unimplemented: + +void __ubsan_handle_implicit_conversion(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo); +void __ubsan_handle_implicit_conversion_abort(struct CImplicitConversionData *pData, unsigned long ulFrom, unsigned long ulTo); +void __ubsan_handle_nonnull_arg(struct CNonNullArgData *pData); +void __ubsan_handle_nonnull_arg_abort(struct CNonNullArgData *pData); +void __ubsan_handle_nonnull_return_v1(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_nonnull_return_v1_abort(struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +void __ubsan_handle_float_cast_overflow(struct CFloatCastOverflowData *pData, unsigned long ulFrom); +void __ubsan_handle_float_cast_overflow_abort(struct CFloatCastOverflowData *pData, unsigned long ulFrom); +void __ubsan_handle_dynamic_type_cache_miss(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +void __ubsan_handle_dynamic_type_cache_miss_abort(struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +void __ubsan_handle_cfi_bad_type(struct CCFICheckFailData *pData, unsigned long ulVtable, bool bValidVtable, bool FromUnrecoverableHandler, unsigned long ProgramCounter, unsigned long FramePointer); +void __ubsan_handle_cfi_check_fail(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable); +void __ubsan_handle_cfi_check_fail_abort(struct CCFICheckFailData *pData, unsigned long ulValue, unsigned long ulValidVtable); +#endif + +static void HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation); +static void HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue); +static void HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData); +static void HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer); +static void HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound); +static void HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex); +static void HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS); +static void HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue); +static void HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData); +static void HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction); +static void HandleMissingReturn(bool isFatal, struct CUnreachableData *pData); +static void HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult); +static void HandleAlignmentAssumption(bool isFatal, struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset); + +#if 0 +Unimplemented: + +static void HandleCFIBadType(bool isFatal, struct CCFICheckFailData *pData, unsigned long ulVtable, bool *bValidVtable, bool *FromUnrecoverableHandler, unsigned long *ProgramCounter, unsigned long *FramePointer); +static void HandleNonnullArg(bool isFatal, struct CNonNullArgData *pData); +static void HandleNonnullReturn(bool isFatal, struct CNonNullReturnData *pData, struct CSourceLocation *pLocationPointer); +static void HandleDynamicTypeCacheMiss(bool isFatal, struct CDynamicTypeCacheMissData *pData, unsigned long ulPointer, unsigned long ulHash); +static void HandleFloatCastOverflow(bool isFatal, struct CFloatCastOverflowData *pData, unsigned long ulFrom); +#endif + + +#define NUMBER_SIGNED_BIT 1 +#define NUMBER_MAXLEN 128 +#define __arraycount(__a) (sizeof(__a) / sizeof(__a[0])) +#define __BIT(__n) (1UL << (__n)) +#define SEPARATOR sbi_printf("===========================================\n") +#define ACK_REPORTED (1U << 31) + +static bool isAlreadyReported(struct CSourceLocation *pLocation) +{ + uint32_t siOldValue; + volatile uint32_t *pLine; + + if (!pLocation) + return false; + + pLine = &pLocation->mLine; + + do { + siOldValue = *pLine; + } while (__sync_val_compare_and_swap(pLine, siOldValue, siOldValue | ACK_REPORTED) != siOldValue); + + return ((siOldValue) & (ACK_REPORTED)); +} + +static void HandleOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS, const char *szOperation) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + bool is_signed = pData->mType->mTypeInfo & NUMBER_SIGNED_BIT; + + sbi_printf("UBSan: %s integer overflow: ", is_signed ? "signed" : "unsigned"); + + if (is_signed){ + sbi_printf("%ld %s %ld ",(long)ulLHS, szOperation, (long)ulRHS); + } + else{ + sbi_printf("%lu %s %lu ", ulLHS, szOperation, ulRHS); + } + + sbi_printf("cannot be represented in type %s\n", pData->mType->mTypeName); + + SEPARATOR; +} + +static void HandleNegateOverflow(bool isFatal, struct COverflowData *pData, unsigned long ulOldValue) +{ + if(!pData) + { + return; + } + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + bool is_signed = pData->mType->mTypeInfo & NUMBER_SIGNED_BIT; + + sbi_printf("UBSan: Negation of "); + + if (is_signed){ + sbi_printf("%ld", (long)ulOldValue); + } + else{ + sbi_printf("%lu", ulOldValue); + } + + sbi_printf("cannot be represented in type %s\n", pData->mType->mTypeName); + + SEPARATOR; +} + +static void HandleBuiltinUnreachable(bool isFatal, struct CUnreachableData *pData) +{ + if(!pData) + { + return; + } + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + SEPARATOR; +} + +const char *rgczTypeCheckKinds[] = { + "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", + "_Nonnull binding to", + "dynamic operation on" +}; + +static void HandleTypeMismatch(bool isFatal, struct CSourceLocation *mLocation, struct CTypeDescriptor *mType, unsigned long mLogAlignment, uint8_t mTypeCheckKind, unsigned long ulPointer) +{ + + if((!mLocation) || (!mType)) { + return; + } + + if (isAlreadyReported(mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + mLocation->mFilename, + mLocation->mLine & ~ACK_REPORTED, + mLocation->mColumn); + + const char *kind = (mTypeCheckKind < __arraycount(rgczTypeCheckKinds)) ? rgczTypeCheckKinds[mTypeCheckKind] : "access to"; + + if (ulPointer == 0) { + sbi_printf("%s null pointer of type %s\n", kind, mType->mTypeName); + } + else if ((mLogAlignment - 1) & ulPointer) { //mLogAlignment is converted on the wrapper function call + sbi_printf("%s misaligned address %p for type %s which requires %ld byte alignment\n", kind, (void *)ulPointer, mType->mTypeName, mLogAlignment); + } + else { + sbi_printf("%s address %p with insufficient space for an object of type %s\n", kind, (void*)ulPointer, mType->mTypeName); + } + SEPARATOR; +} + +static void HandleVlaBoundNotPositive(bool isFatal, struct CVLABoundData *pData, unsigned long ulBound) +{ + if(!pData) + { + return; + } + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + sbi_printf("variable length array bound value "); + + bool is_signed = pData->mType->mTypeInfo & NUMBER_SIGNED_BIT; + + if (is_signed){ + sbi_printf("%ld", (long)ulBound); + } + else{ + sbi_printf("%lu", ulBound); + } + + sbi_printf(" <= 0\n"); + + SEPARATOR; +} + +static void HandleOutOfBounds(bool isFatal, struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + if(!pData) + { + return; + } + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + bool is_signed = pData->mIndexType->mTypeInfo & NUMBER_SIGNED_BIT; + + if (is_signed){ + sbi_printf("index %ld", (long)ulIndex); + } + else{ + sbi_printf("index %lu", ulIndex); + } + + sbi_printf(" is out of range for type %s\n", pData->mArrayType->mTypeName); + + SEPARATOR; +} + +static bool isNegativeNumber(struct CTypeDescriptor *pType, unsigned long ulVal) +{ + if (!(pType->mTypeInfo & NUMBER_SIGNED_BIT)) + { + return false; + } + + return (long)ulVal < 0; +} + +static size_t type_width(struct CTypeDescriptor *pType) +{ + return 1UL << (pType->mTypeInfo >> 1); +} + +static void HandleShiftOutOfBounds(bool isFatal, struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + if (isNegativeNumber(pData->mRHSType, ulRHS)) { + sbi_printf("shift exponent %ld is negative\n", (long)ulRHS); + } + else if (ulRHS >= type_width(pData->mLHSType)) { + sbi_printf("shift exponent %lu is too large for %lu-bit type %s\n", ulRHS, (unsigned long)type_width(pData->mLHSType), pData->mLHSType->mTypeName); + + } + else if (isNegativeNumber(pData->mLHSType, ulLHS)) { + sbi_printf("left shift of negative value %ld\n", (long)ulLHS); + } + else { + sbi_printf("left shift of %lu by %lu places cannot be represented in type %s\n", ulLHS, ulRHS, pData->mLHSType->mTypeName); + } + + SEPARATOR; +} + +static void HandleLoadInvalidValue(bool isFatal, struct CInvalidValueData *pData, unsigned long ulValue) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + bool is_signed = pData->mType->mTypeInfo & NUMBER_SIGNED_BIT; + + sbi_printf("load of value "); + + if (is_signed){ + sbi_printf("%ld ", (long)ulValue); + } + else{ + sbi_printf("%lu ", ulValue); + } + + sbi_printf("is not a valid value for type %s\n", pData->mType->mTypeName); + + SEPARATOR; +} + +const char *rgczBuiltinCheckKinds[] = { + "ctz()", + "clz()" +}; + + +static void HandleInvalidBuiltin(bool isFatal, struct CInvalidBuiltinData *pData) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + const char *builtin = (pData->mKind < __arraycount(rgczBuiltinCheckKinds)) ? rgczBuiltinCheckKinds[pData->mKind] : "unknown builtin"; + + sbi_printf("passing zero to %s, which is not a valid argument\n", builtin); + + SEPARATOR; +} + +static void HandleFunctionTypeMismatch(bool isFatal, struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + + sbi_printf("call to function %#lx through pointer to incorrect function type %s\n", ulFunction, pData->mType->mTypeName); + + SEPARATOR; +} + +static void HandleMissingReturn(bool isFatal, struct CUnreachableData *pData) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + sbi_printf("execution reached the end of a value-returning function without returning a value\n"); + + SEPARATOR; +} + +static void HandlePointerOverflow(bool isFatal, struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + sbi_printf("pointer expression with base %#lx overflowed to %#lx\n", ulBase, ulResult); + + SEPARATOR; +} + +static void HandleAlignmentAssumption(bool isFatal, struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset) +{ + + if(!pData) + { + return; + } + + if (isAlreadyReported(&pData->mLocation)) + { + return; + } + + SEPARATOR; + + sbi_printf("UBSan: Undefined Behavior in %s:%u:%u\n", + pData->mLocation.mFilename, + pData->mLocation.mLine & ~ACK_REPORTED, + pData->mLocation.mColumn); + + unsigned long ulRealPointer = ulPointer - ulOffset; + sbi_printf("alignment assumption of %lu for pointer %p (offset %p)", ulAlignment, (void*) ulRealPointer, (void*) ulOffset); + + if (pData->mAssumptionLocation.mFilename != NULL) { + sbi_printf(", assumption made in %s:%u:%u", + pData->mAssumptionLocation.mFilename, + pData->mAssumptionLocation.mLine, + pData->mAssumptionLocation.mColumn); + } + + sbi_printf("\n"); + + SEPARATOR; +} + +/* Definions of public symbols emitted by the instrumentation code */ +void __ubsan_handle_add_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(false, pData, ulLHS, ulRHS, "+"); +} + +void __ubsan_handle_add_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(true, pData, ulLHS, ulRHS, "+"); +} + +void __ubsan_handle_sub_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(false, pData, ulLHS, ulRHS, "-"); +} + +void __ubsan_handle_sub_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(true, pData, ulLHS, ulRHS, "-"); +} + +void __ubsan_handle_mul_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(false, pData, ulLHS, ulRHS, "*"); +} + +void __ubsan_handle_mul_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(true, pData, ulLHS, ulRHS, "*"); +} + +void __ubsan_handle_negate_overflow(struct COverflowData *pData, unsigned long ulOldValue) +{ + HandleNegateOverflow(false, pData, ulOldValue); +} + +void __ubsan_handle_negate_overflow_abort(struct COverflowData *pData, unsigned long ulOldValue) +{ + HandleNegateOverflow(true, pData, ulOldValue); +} + +void __ubsan_handle_divrem_overflow(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(false, pData, ulLHS, ulRHS, "divrem"); +} + +void __ubsan_handle_divrem_overflow_abort(struct COverflowData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleOverflow(true, pData, ulLHS, ulRHS, "divrem"); +} + +void __ubsan_handle_type_mismatch_v1(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer) +{ + HandleTypeMismatch(false, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer); +} + +void __ubsan_handle_type_mismatch_v1_abort(struct CTypeMismatchData_v1 *pData, unsigned long ulPointer) +{ + HandleTypeMismatch(true, &pData->mLocation, pData->mType, __BIT(pData->mLogAlignment), pData->mTypeCheckKind, ulPointer); +} + +void __ubsan_handle_out_of_bounds(struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + HandleOutOfBounds(false, pData, ulIndex); +} + +void __ubsan_handle_out_of_bounds_abort(struct COutOfBoundsData *pData, unsigned long ulIndex) +{ + HandleOutOfBounds(true, pData, ulIndex); +} + +void __ubsan_handle_shift_out_of_bounds(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleShiftOutOfBounds(false, pData, ulLHS, ulRHS); +} + +void __ubsan_handle_shift_out_of_bounds_abort(struct CShiftOutOfBoundsData *pData, unsigned long ulLHS, unsigned long ulRHS) +{ + HandleShiftOutOfBounds(true, pData, ulLHS, ulRHS); +} + +void __ubsan_handle_pointer_overflow(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + HandlePointerOverflow(false, pData, ulBase, ulResult); +} + +void __ubsan_handle_pointer_overflow_abort(struct CPointerOverflowData *pData, unsigned long ulBase, unsigned long ulResult) +{ + HandlePointerOverflow(true, pData, ulBase, ulResult); +} + +void __ubsan_handle_alignment_assumption(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset) +{ + HandleAlignmentAssumption(false, pData, ulPointer, ulAlignment, ulOffset); +} + +void __ubsan_handle_alignment_assumption_abort(struct CAlignmentAssumptionData *pData, unsigned long ulPointer, unsigned long ulAlignment, unsigned long ulOffset) +{ + HandleAlignmentAssumption(true, pData, ulPointer, ulAlignment, ulOffset); +} + +void __ubsan_handle_builtin_unreachable(struct CUnreachableData *pData) +{ + HandleBuiltinUnreachable(true, pData); +} + +void __ubsan_handle_invalid_builtin(struct CInvalidBuiltinData *pData) +{ + HandleInvalidBuiltin(true, pData); +} + +void __ubsan_handle_invalid_builtin_abort(struct CInvalidBuiltinData *pData) +{ + HandleInvalidBuiltin(true, pData); +} + +void __ubsan_handle_load_invalid_value(struct CInvalidValueData *pData, unsigned long ulValue) +{ + HandleLoadInvalidValue(false, pData, ulValue); +} + +void __ubsan_handle_load_invalid_value_abort(struct CInvalidValueData *pData, unsigned long ulValue) +{ + HandleLoadInvalidValue(true, pData, ulValue); +} + +void __ubsan_handle_missing_return(struct CUnreachableData *pData) +{ + HandleMissingReturn(true, pData); +} + +void __ubsan_handle_vla_bound_not_positive(struct CVLABoundData *pData, unsigned long ulBound) +{ + HandleVlaBoundNotPositive(false, pData, ulBound); +} + +void __ubsan_handle_vla_bound_not_positive_abort(struct CVLABoundData *pData, unsigned long ulBound) +{ + HandleVlaBoundNotPositive(true, pData, ulBound); +} + +void __ubsan_handle_function_type_mismatch(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + HandleFunctionTypeMismatch(false, pData, ulFunction); +} + +void __ubsan_handle_function_type_mismatch_abort(struct CFunctionTypeMismatchData *pData, unsigned long ulFunction) +{ + HandleFunctionTypeMismatch(true, pData, ulFunction); +} +#endif \ 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..487790ef --- /dev/null +++ b/lib/sbi/sbi_ubsan_test.c @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Author: Marcos Oduardo + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef UBSAN_TESTS_ENABLED +#include +#include + +void sbi_ubsan_test_suite(void) +{ + sbi_printf("\n[UBSan Test] Starting NetBSD-based test suite\n"); + + { + sbi_printf("\n[UBSan Test] Add Overflow Test\n"); + volatile int a = 0x7FFFFFFF; + (void)a; + volatile int b = 1; + (void)b; + volatile int c = a + b; + (void)c; + } + + { + sbi_printf("\n[UBSan Test] Sub Overflow Test\n"); + volatile int a = 0x80000000; + (void)a; + volatile int b = 1; + (void)b; + volatile int c = a - b; + (void)c; + } + + { + sbi_printf("\n[UBSan Test] Mul Overflow Test\n"); + volatile int a = 0x7FFFFFFF; + (void)a; + volatile int b = 2; + (void)b; + volatile int c = a * b; + (void)c; + } + + { + sbi_printf("\n[UBSan Test] Div/Rem Overflow Test\n"); + volatile int a = 10; + (void)a; + volatile int b = 0; + (void)b; + volatile int c = a / b; + (void)c; + } + + { + sbi_printf("\n[UBSan Test] Index Out of Bounds Test\n"); + volatile int idx = 5; + (void)idx; + int arr[3] = {1, 2, 3}; + volatile int val = arr[idx]; + (void)val; + } + + { + sbi_printf("\n[UBSan Test] Shift Exponent Too Large Test\n"); + volatile unsigned long val = 1; + (void)val; + volatile int shift = 64; + (void)shift; + volatile unsigned long res = val << shift; + (void)res; + } + + { + sbi_printf("\n[UBSan Test] Shift Exponent Negative Test\n"); + volatile int val = 1; + (void)val; + volatile int shift = -1; + (void)shift; + volatile int res = val << shift; + (void)res; + } + + { + sbi_printf("\n[UBSan Test] Misaligned Access Test\n"); + char buffer[16] __attribute__((aligned(16))); + volatile int *ptr = (int *)&buffer[1]; + (void)ptr; + volatile int val = *ptr; + (void)val; + } + + { + sbi_printf("\n[UBSan Test] Null Dereference Test\n"); + volatile int *ptr = NULL; + (void)ptr; + sbi_printf("\n[UBSan Test] Uncomment next two lines of code for testing Null dereference\n"); + + //volatile int val = *ptr; + //(void)val; + } + + { + sbi_printf("\n[UBSan Test] Load Invalid Value Test\n"); + volatile char bool_val = 5; + (void)bool_val; + volatile bool *b_ptr = (bool *)&bool_val; + (void)b_ptr; + if (*b_ptr) { (void)0; } + } + + { + sbi_printf("\n[UBSan Test] Pointer Overflow Test\n"); + volatile uintptr_t base = 0xFFFFFFFFFFFFFFFEUL; + (void)base; + volatile char *ptr = (char *)base; + (void)ptr; + volatile char *res = ptr + 5; + (void)res; + } + + sbi_printf("\n[UBSan Test] All tests dispatched successfully.\n\n"); +} +#endif \ No newline at end of file -- 2.53.0 -- opensbi mailing list opensbi@lists.infradead.org http://lists.infradead.org/mailman/listinfo/opensbi