From 28aa11e291c592920225e56f213c4835b5f6792b Mon Sep 17 00:00:00 2001 From: Eric Chan Date: Wed, 10 Jul 2024 17:39:01 +0000 Subject: [PATCH 1/4] [include][sys][types.h] Let LK support 32/64bit machines in ssize_t format specifies type 'ssize_t' (aka 'int') but the argument has type 'ssize_t' (aka 'long') [-Werror,-Wformat] 104 | snprintf(s.buf, 36, "%zd", (ssize_t)val_); | ~~~ ^~~~~~~~~~~~~ | %zd ssize_t should be the signed variant of size_t. size_t is a typedef to __SIZE_TYPE__ and both clang and gcc define __SIZE_TYPE__ as unsigned int for 32-bit platforms. But there's no __SSIZE_TYPE__ definition. ssize_t should be signed int instead of signed long (even though they are the same size). And fixed the format warning which use ssize_t but format is not zd. --- app/tests/v9fs_tests.c | 2 +- arch/arm/arm/debug.c | 3 +-- lib/bio/debug.c | 14 +++++++------- lib/fs/9p/dir.c | 2 +- lib/fs/spifs/test/spifstest.c | 4 ++-- lib/libc/include/sys/types.h | 4 ++++ lib/minip/tcp.c | 5 ++--- lib/minip/udp.c | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/app/tests/v9fs_tests.c b/app/tests/v9fs_tests.c index c6d9ac9bda..5170be85c8 100644 --- a/app/tests/v9fs_tests.c +++ b/app/tests/v9fs_tests.c @@ -43,7 +43,7 @@ int v9fs_tests(int argc, const console_cmd_args *argv) { readbytes = fs_read_file(handle, buf, 0, BUF_SIZE); if (readbytes < 0) { - LOGF("failed to read the target file: %ld\n", readbytes); + LOGF("failed to read the target file: %zd\n", readbytes); return status; } diff --git a/arch/arm/arm/debug.c b/arch/arm/arm/debug.c index bcc6de61b3..d48dfd8ed6 100644 --- a/arch/arm/arm/debug.c +++ b/arch/arm/arm/debug.c @@ -165,7 +165,7 @@ static int cmd_dcc(int argc, const console_cmd_args *argv) { uint32_t buf[128]; ssize_t len = arm_dcc_read(buf, sizeof(buf), 1000); - printf("arm_dcc_read returns %ld\n", len); + printf("arm_dcc_read returns %zd\n", len); if (len > 0) { hexdump(buf, len); } @@ -181,4 +181,3 @@ STATIC_COMMAND_START STATIC_COMMAND("dcc", "dcc stuff", &cmd_dcc) #endif STATIC_COMMAND_END(dcc); - diff --git a/lib/bio/debug.c b/lib/bio/debug.c index 91d515d97a..0cf2e299a9 100644 --- a/lib/bio/debug.c +++ b/lib/bio/debug.c @@ -125,7 +125,7 @@ static int cmd_bio(int argc, const console_cmd_args *argv) { ssize_t err_len = bio_read(dev, buf, offset, amt); if (err_len < 0) { - dprintf(ALWAYS, "read error %s %zu@%zu (err_len %ld)\n", + dprintf(ALWAYS, "read error %s %zu@%zu (err_len %zd)\n", argv[2].str, amt, (size_t)offset, err_len); break; } @@ -413,7 +413,7 @@ static status_t memory_mapped_test(bdev_t *device) { // Erase the first page of the Device. ssize_t err = bio_erase(device, 0, device->block_size); if (err < (ssize_t)device->block_size) { - printf("Expected to erase at least %zu bytes but only erased %ld. " + printf("Expected to erase at least %zu bytes but only erased %zd. " "Not continuing to test memory mapped mode.\n", device->block_size, err); retcode = ERR_IO; @@ -430,7 +430,7 @@ static status_t memory_mapped_test(bdev_t *device) { err = bio_write_block(device, test_buffer, 0, 1); if (err != (ssize_t)device->block_size) { printf("Error while writing test pattern to device. Expected to write " - "%zu bytes but actually wrote %ld. Not continuing to test memory " + "%zu bytes but actually wrote %zd. Not continuing to test memory " "mapped mode.\n", device->block_size, err); retcode = ERR_IO; goto finish; @@ -474,7 +474,7 @@ static status_t memory_mapped_test(bdev_t *device) { // what we wrote back earlier. err = bio_read_block(device, reference_buffer, 0, 1); if (err != (ssize_t)device->block_size) { - printf("Expected to read %zu bytes, actually read %ld. Aborting.\n", + printf("Expected to read %zu bytes, actually read %zd. Aborting.\n", device->block_size, err); retcode = ERR_IO; goto finish; @@ -501,10 +501,10 @@ static status_t memory_mapped_test(bdev_t *device) { static int bio_test_device(bdev_t *device) { ssize_t num_errors = erase_test(device); if (num_errors < 0) { - printf("error %ld performing erase test\n", num_errors); + printf("error %zd performing erase test\n", num_errors); return -1; } - printf("discovered %ld error(s) while testing erase.\n", num_errors); + printf("discovered %zd error(s) while testing erase.\n", num_errors); if (num_errors) { // No point in continuing the tests if we couldn't erase the device. printf("not continuing to test writes.\n"); @@ -512,7 +512,7 @@ static int bio_test_device(bdev_t *device) { } num_errors = write_test(device); - printf("Discovered %ld error(s) while testing write.\n", num_errors); + printf("Discovered %zd error(s) while testing write.\n", num_errors); if (num_errors) { return -1; } diff --git a/lib/fs/9p/dir.c b/lib/fs/9p/dir.c index 5cdb328490..ddd2f701fb 100644 --- a/lib/fs/9p/dir.c +++ b/lib/fs/9p/dir.c @@ -268,7 +268,7 @@ status_t v9fs_read_dir(dircookie *dcookie, struct dirent *ent) } LTRACEF( - "head (%u) tail (%u) sread (%ld) offset (%llu) name " + "head (%u) tail (%u) sread (%zd) offset (%llu) name " "(%s)\n", dir->head, dir->tail, sread, p9_dent.offset, p9_dent.name); diff --git a/lib/fs/spifs/test/spifstest.c b/lib/fs/spifs/test/spifstest.c index 5258bc14d8..a3fcfad4af 100644 --- a/lib/fs/spifs/test/spifstest.c +++ b/lib/fs/spifs/test/spifstest.c @@ -731,7 +731,7 @@ static int spifs_bench(int argc, const console_cmd_args *argv) { if (n_bytes < 0) { printf("SPIFS Benchmark Failed to write to file at %s. " - "Reason = %ld.\n", test_file_path, n_bytes); + "Reason = %zd.\n", test_file_path, n_bytes); retcode = -1; fs_close_file(handle); goto finish; @@ -752,7 +752,7 @@ static int spifs_bench(int argc, const console_cmd_args *argv) { if (n_bytes < 0) { printf("SPIFS Benchmark Failed to read from file at %s. " - "Reason = %ld.\n", test_file_path, n_bytes); + "Reason = %zd.\n", test_file_path, n_bytes); retcode = -1; fs_close_file(handle); goto finish; diff --git a/lib/libc/include/sys/types.h b/lib/libc/include/sys/types.h index be9302de84..47dc97e8fe 100644 --- a/lib/libc/include/sys/types.h +++ b/lib/libc/include/sys/types.h @@ -44,7 +44,11 @@ enum handler_return { INT_RESCHEDULE, }; +#ifdef __LP64__ typedef signed long int ssize_t; +#else +typedef signed int ssize_t; +#endif typedef uint8_t u8; typedef uint16_t u16; diff --git a/lib/minip/tcp.c b/lib/minip/tcp.c index 8960faade7..2831dc146c 100644 --- a/lib/minip/tcp.c +++ b/lib/minip/tcp.c @@ -1330,7 +1330,7 @@ static int cmd_tcp(int argc, const console_cmd_args *argv) { uint8_t buf[512]; ssize_t err_len = tcp_read(accepted, buf, sizeof(buf)); - printf("tcp_read returns %ld\n", err_len); + printf("tcp_read returns %zd\n", err_len); if (err_len < 0) break; if (err_len > 0) { @@ -1338,7 +1338,7 @@ static int cmd_tcp(int argc, const console_cmd_args *argv) { } err_len = tcp_write(accepted, buf, err_len); - printf("tcp_write returns %ld\n", err_len); + printf("tcp_write returns %zd\n", err_len); if (err_len < 0) break; } @@ -1362,4 +1362,3 @@ static int cmd_tcp(int argc, const console_cmd_args *argv) { STATIC_COMMAND_START STATIC_COMMAND("tcp", "tcp commands", &cmd_tcp) STATIC_COMMAND_END(tcp); - diff --git a/lib/minip/udp.c b/lib/minip/udp.c index de4d5240d0..f7a63f3acf 100644 --- a/lib/minip/udp.c +++ b/lib/minip/udp.c @@ -148,7 +148,7 @@ status_t udp_send_iovec(const iovec_t *iov, uint iov_count, udp_socket_t *handle udp->chksum = rfc768_chksum(ip, udp); #endif - LTRACEF("packet paylod len %ld\n", len); + LTRACEF("packet paylod len %zd\n", len); minip_tx_handler(minip_tx_arg, p); From 0ee8e25677e536800e9b60ec9c94b2c462fd5023 Mon Sep 17 00:00:00 2001 From: Eric Chan Date: Wed, 10 Jul 2024 17:55:36 +0000 Subject: [PATCH 2/4] [external][ARM][CMSIS] prevent compilation error with C++ C++ have different behavior for const qualifier. The const qualifier used on a declaration of a non-local non-volatile non-template(since C++14)non-inline(since C++17) variable that is not declared extern gives it internal linkage. This is different from C where const file scope variables have external linkage. So add __BEGIN_CDECLS/__END_CDECLS to prevent compilation error. Original compilation error as below: arm-m/CMSIS/Include/cmsis_gcc.h:149:31: error: variable '__copy_table_start__' is used but not defined in this translation unit, and cannot be defined in any other translation unit because its type does not have linkage 149 | extern const __copy_table_t __copy_table_start__; | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:154:40: note: used here 154 | for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) { | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:150:31: error: variable '__copy_table_end__' is used but not defined in this translation unit, and cannot be defined in any other translation unit because its type does not have linkage 150 | extern const __copy_table_t __copy_table_end__; | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:154:72: note: used here 154 | for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) { | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:151:31: error: variable '__zero_table_start__ ' is used but not defined in this translation unit, and cannot be defined in any other translation uni t because its type does not have linkage 151 | exterlinking build-gdmc/gsp/platform/gsp/debugger.mod.on const __zero_table_t __zero_table_start__; | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:160:40: note: used here 160 | for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:151:31: error: variable '__zero_table_start__ ' is used but not defined in this translation unit, and cannot be defined in any other translation uni t because its type does not have linkage 151 | exterlinking build-gdmc/gsp/platform/gsp/debugger.mod.on const __zero_table_t __zero_table_start__; | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:160:40: note: used here 160 | for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:152:31: error: variable '__zero_table_end__' is used but not defined in this translation unit, and cannot be defined in any other translation unit because its type does not have linkage 152 | extern const __zero_table_t __zero_table_end__; | ^ lk/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h:160:72: note: used here 160 | for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { | --- external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h b/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h index dc3ae357fc..7fb51ac59e 100644 --- a/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h +++ b/external/arch/arm/arm-m/CMSIS/Include/cmsis_gcc.h @@ -27,6 +27,7 @@ /* LK: include lk's compiler.h first, which has some of the same #defines */ #include +__BEGIN_CDECLS /* ignore some GCC warnings */ #pragma GCC diagnostic push @@ -2211,4 +2212,5 @@ __STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) #pragma GCC diagnostic pop +__END_CDECLS #endif /* __CMSIS_GCC_H */ From dbf485d61cd40fa20f025ecb6012b114463618ea Mon Sep 17 00:00:00 2001 From: Eric Chan Date: Wed, 10 Jul 2024 17:58:37 +0000 Subject: [PATCH 3/4] [ubsan] Add some handlers that do not yet exist and fix some format errors Add handlers as below: 1. __ubsan_handle_function_type_mismatch 2. __ubsan_handle_alignment_assumption 3. __ubsan_handle_float_cast_overflow Also fix the format errors for compiling and printing. Test log is as below: start test_ubsan_function_type_mismatch ... ===================================UBSAN error=================================== ubsan: function type mismatch in lk/lib/test_ubsan/test_ubsan.c:191:5 Call function(0x12e8d) through pointer with incompatible type 'void (*)(void)' ================================================================================= start test_ubsan_alignment_assumption ... alignment assumption ===================================UBSAN error=================================== ubsan: Alignment Error in lk/lib/test_ubsan/test_ubsan.c:217:11 assumption of 32 byte alignment for pointer of type 'void *' failed address is 2 aligned, misalignment offset is 3 bytes ================================================================================= alignment assumption offset ===================================UBSAN error=================================== ubsan: Alignment Error in lk/lib/test_ubsan/test_ubsan.c:218:11 assumption of 32 byte alignment (with offset of 4 byte) for pointer of type 'void *' failed offset address is 2 aligned, misalignment offset is 31 bytes ================================================================================= start test_ubsan_float_cast_overflow ... ===================================UBSAN error=================================== ubsan: Float Cast Overflow in lk/lib/test_ubsan/test_ubsan.c:82:12 value 'double' is outside of the range of representable value of type 'unsigned int' at 0x2001d3e8 ================================================================================= --- lib/ubsan/ubsan.cpp | 80 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 3 deletions(-) diff --git a/lib/ubsan/ubsan.cpp b/lib/ubsan/ubsan.cpp index 1f09f43f86..cab3b831cf 100644 --- a/lib/ubsan/ubsan.cpp +++ b/lib/ubsan/ubsan.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -172,7 +173,7 @@ static void ubsan_report_end() static void do_ubsan_type_mismatch_nullptr(const ubsan_type_mismatch_data *data, size_t ptr) { ubsan_report_start(&data->location, "Null pointer dereference"); - printf("%s null pointer of type %sn", type_check_kinds[data->type_check_kind], + printf("%s null pointer of type %s\n", type_check_kinds[data->type_check_kind], data->type->typename_); ubsan_report_end(); } @@ -189,7 +190,7 @@ static void do_ubsan_type_mismatch_unaligned(const ubsan_type_mismatch_data *dat static void do_ubsan_type_mismatch_objsize(const ubsan_type_mismatch_data *data, size_t ptr) { ubsan_report_start(&data->location, "Insufficient object size"); - printf("%s address %p with insuficient space for type %s\n", + printf("%s address %p with insufficient space for type %s\n", type_check_kinds[data->type_check_kind], (void *) ptr, data->type->typename_); ubsan_report_end(); } @@ -314,7 +315,7 @@ static void ubsan_handle_integer_overflow(const ubsan_overflow_data *data, size_ ubsan_report_start(&data->location, "Integer overflow"); - printf("%s integer overflow: %s %s %s can't be represented in type %s", + printf("%s integer overflow: %s %s %s can't be represented in type %s\n", signed_ ? "signed" : "unsigned", lhs_v.to_string().c_str(), op, rhs_v.to_string().c_str(), data->type->typename_); ubsan_report_end(); @@ -557,6 +558,79 @@ __USED void __ubsan_handle_vla_bound_not_positive_abort(ubsan_vla_bound_data *da ubsan_abort(); } +struct ubsan_function_type_mismatch_data { + ubsan_source_location location; + ubsan_type_descriptor *type; + val function_ptr; +}; + +__USED void __ubsan_handle_function_type_mismatch(ubsan_function_type_mismatch_data *data, size_t ptr) +{ + ubsan_report_start(&data->location, "function type mismatch"); + printf("Call function(%p) through pointer with incompatible type %s\n", + (void *) ptr, data->type->typename_); + ubsan_report_end(); +} + +__USED void __ubsan_handle_function_type_mismatch_abort(ubsan_function_type_mismatch_data *data, size_t ptr) +{ + __ubsan_handle_function_type_mismatch(data, ptr); + ubsan_abort(); +} + +struct ubsan_alignment_assumption_data { + struct ubsan_source_location location; + struct ubsan_source_location assumption_location; + struct ubsan_type_descriptor *type; +}; + +__USED void __ubsan_handle_alignment_assumption(ubsan_alignment_assumption_data *data, ssize_t ptr, + ssize_t align, ssize_t offset) +{ + ssize_t real_ptr; + ubsan_report_start(&data->location, "Alignment Error"); + if (offset) + printf("assumption of %zd byte alignment (with offset of %zd byte) for pointer of type %s failed", + align, offset, data->type->typename_); + else + printf("assumption of %zd byte alignment for pointer of type %s failed", + align, data->type->typename_); + + real_ptr = ptr - offset; + printf(" %saddress is %lu aligned, misalignment offset is %zd bytes\n", + offset ? "offset " : "", real_ptr ? (1 << ffs(real_ptr)) : 1, + real_ptr & (align - 1)); + + ubsan_report_end(); +} + +__USED void __ubsan_handle_alignment_assumption_abort(ubsan_alignment_assumption_data *data, + ssize_t ptr, ssize_t align, ssize_t offset) +{ + __ubsan_handle_alignment_assumption(data, ptr, align, offset); + ubsan_abort(); +} + +struct ubsan_float_cast_data { + struct ubsan_source_location location; + struct ubsan_type_descriptor *from_type; + struct ubsan_type_descriptor *to_type; +}; + +__USED void __ubsan_handle_float_cast_overflow(ubsan_float_cast_data *data, size_t ptr) +{ + ubsan_report_start(&data->location, "Float Cast Overflow"); + printf("value %s is outside of the range of representable value of type %s at %p\n", + data->from_type->typename_, data->to_type->typename_, (void *) ptr); + ubsan_report_end(); +} + +__USED void __ubsan_handle_float_cast_overflow_abort(ubsan_float_cast_data *data, size_t ptr) +{ + __ubsan_handle_float_cast_overflow(data, ptr); + ubsan_abort(); +} + // Note: we used to have __ubsan_handle_function_type_mismatch but it seems to have been dropped // from both GCC and clang From 7e1789e32229355018086b12aae113d943b69e41 Mon Sep 17 00:00:00 2001 From: Eric Chan Date: Wed, 10 Jul 2024 18:01:18 +0000 Subject: [PATCH 4/4] [test_ubsan] Add test_ubsan for testing all ubsan handler behavior Some of platforms may have the memory limitation so can not enable UBSAN directly. So add a test module for ubsan. Test log is as below: test_ubsan Usage: test_ubsan [OPTION] NUM - The testcase number you want to test all - executing all ubsan test cases Available ubsan test cases: Num: testcase name 0: add_overflow 1: sub_overflow 2: mul_overflow 3: negate_overflow 4: pointer_overflow 5: float_cast_overflow 6: shift_out_of_bounds_overflow 7: shift_out_of_bounds_negative 8: out_of_bounds_overflow 9: out_of_bounds_underflow 10: load_invalid_value_bool 11: load_invalid_value_enum 12: nullptr_deref 13: misaligned_access 14: object_size_mismatch 15: function_type_mismatch 16: nonnull_arg 17: nonnull_return 18: vla_bound_not_positive 19: alignment_assumption 20: alignment_assumption_offset 21: invalid_builtin_clz 22: invalid_builtin_ctz 23: builtin_unreachable test_ubsan all start add_overflow ... ===================================UBSAN error=================================== ubsan: Integer overflow in lk/lib/test_ubsan/test_ubsan.c:25:9 signed integer overflow: 2147483647 + 2 can't be represented in type 'int' ================================================================================= start sub_overflow ... ===================================UBSAN error=================================== ubsan: Integer overflow in lk/lib/test_ubsan/test_ubsan.c:32:9 signed integer overflow: -2147483648 - 2 can't be represented in type 'int' ================================================================================= start mul_overflow ... ===================================UBSAN error=================================== ubsan: Integer overflow in lk/lib/test_ubsan/test_ubsan.c:39:9 signed integer overflow: 1073741823 * 3 can't be represented in type 'int' ================================================================================= start negate_overflow ... ===================================UBSAN error=================================== ubsan: Negation overflow in lk/lib/test_ubsan/test_ubsan.c:45:11 Negation of -2147483648 cannot be represented in type 'int' ================================================================================= start pointer_overflow ... ===================================UBSAN error=================================== ubsan: ptr overflow in lk/lib/test_ubsan/test_ubsan.c:60:9 ptr operation overflowed 0x2001d590 to 0x2001d58f ================================================================================= start float_cast_overflow ... ===================================UBSAN error=================================== ubsan: Float Cast Overflow in lk/lib/test_ubsan/test_ubsan.c:68:12 value 'double' is outside of the range of representable value of type 'unsigned int' at 0x2001d580 ================================================================================= start shift_out_of_bounds_overflow ... ===================================UBSAN error=================================== ubsan: shift-oob in lk/lib/test_ubsan/test_ubsan.c:76:9 left shift of 2147483647 by 1 places cannot be represented in type 'volatile int' ================================================================================= start shift_out_of_bounds_negative ... ===================================UBSAN error=================================== ubsan: shift-oob in lk/lib/test_ubsan/test_ubsan.c:83:9 shift exponent -1 is negative ================================================================================= start out_of_bounds_overflow ... ===================================UBSAN error=================================== ubsan: out of bounds in lk/lib/test_ubsan/test_ubsan.c:94:5 index 4 out of range for type 'volatile int[4]' (4) ================================================================================= start out_of_bounds_underflow ... ===================================UBSAN error=================================== ubsan: out of bounds in lk/lib/test_ubsan/test_ubsan.c:105:5 index -1 out of range for type 'volatile int[4]' (ffffffff) ================================================================================= start load_invalid_value_bool ... ===================================UBSAN error=================================== ubsan: load invalid value in lk/lib/test_ubsan/test_ubsan.c:117:12 load of value 2, which is not a valid value for type 'bool' ================================================================================= start load_invalid_value_enum ... ===================================UBSAN error=================================== ubsan: load invalid value in lk/lib/test_ubsan/test_ubsan.cpp:7:25 load of value 5, which is not a valid value for type 'volatile enum E' ================================================================================= ===================================UBSAN error=================================== ubsan: load invalid value in lk/lib/test_ubsan/test_ubsan.cpp:8:12 load of value 5, which is not a valid value for type 'volatile enum E' ================================================================================= start nullptr_deref ... ===================================UBSAN error=================================== ubsan: Null pointer dereference in lk/lib/test_ubsan/test_ubsan.c:125:15 load of null pointer of type 'int' ================================================================================= start misaligned_access ... ===================================UBSAN error=================================== ubsan: Unaligned access in lk/lib/test_ubsan/test_ubsan.c:137:10 member access within unaligned pointer 0x2001d58e of type 'struct object' (alignment 4) ================================================================================= ===================================UBSAN error=================================== ubsan: Unaligned access in lk/lib/test_ubsan/test_ubsan.c:137:10 store to unaligned pointer 0x2001d58e of type 'int' (alignment 4) ================================================================================= start object_size_mismatch ... ===================================UBSAN error=================================== ubsan: Insufficient object size in lk/lib/test_ubsan/test_ubsan.c:148:10 member access within address 0x2001d58c with insufficient space for type 'struct object' ================================================================================= ===================================UBSAN error=================================== ubsan: Insufficient object size in lk/lib/test_ubsan/test_ubsan.c:148:10 store to address 0x2001d58c with insufficient space for type 'int' ================================================================================= start function_type_mismatch ... ===================================UBSAN error=================================== ubsan: function type mismatch in lk/lib/test_ubsan/test_ubsan.c:155:5 Call function(0x12d0d) through pointer with incompatible type 'void (*)(void)' ================================================================================= start nonnull_arg ... ===================================UBSAN error=================================== ubsan: nonnull-argument in lk/lib/test_ubsan/test_ubsan.c:161:18 null pointer passed as argument 1, specified non-null ================================================================================= start nonnull_return ... ===================================UBSAN error=================================== ubsan: nonnull return in lk/lib/test_ubsan/test_ubsan.c:164:16 Returning a null pointer from function declared to never return null ================================================================================= start vla_bound_not_positive ... ===================================UBSAN error=================================== ubsan: vla bound not positive in lk/lib/test_ubsan/test_ubsan.c:175:13 vla bound not positive (0) ================================================================================= start alignment_assumption ... ===================================UBSAN error=================================== ubsan: Alignment Error in lk/lib/test_ubsan/test_ubsan.c:195:11 assumption of 32 byte alignment for pointer of type 'void *' failed address is 2 aligned, misalignment offset is 3 bytes ================================================================================= start alignment_assumption_offset ... ===================================UBSAN error=================================== ubsan: Alignment Error in lk/lib/test_ubsan/test_ubsan.c:202:11 assumption of 32 byte alignment (with offset of 4 byte) for pointer of type 'void *' failed offset address is 2 aligned, misalignment offset is 31 bytes ================================================================================= start invalid_builtin_clz ... ===================================UBSAN error=================================== ubsan: invalid builtin in lk/lib/test_ubsan/test_ubsan.c:208:29 Passed 0 to clz() ================================================================================= start invalid_builtin_ctz ... ===================================UBSAN error=================================== ubsan: invalid builtin in lk/lib/test_ubsan/test_ubsan.c:213:29 Passed 0 to ctz() ================================================================================= start builtin_unreachable ... ===================================UBSAN error=================================== ubsan: execution reached an unreachable program point in lk/lib/test_ubsan/test_ubsan.c:218:5 ================================================================================= --- lib/test_ubsan/rules.mk | 14 ++ lib/test_ubsan/test_ubsan.c | 296 ++++++++++++++++++++++++++++++++++ lib/test_ubsan/test_ubsan.cpp | 13 ++ 3 files changed, 323 insertions(+) create mode 100644 lib/test_ubsan/rules.mk create mode 100644 lib/test_ubsan/test_ubsan.c create mode 100644 lib/test_ubsan/test_ubsan.cpp diff --git a/lib/test_ubsan/rules.mk b/lib/test_ubsan/rules.mk new file mode 100644 index 0000000000..a326978b98 --- /dev/null +++ b/lib/test_ubsan/rules.mk @@ -0,0 +1,14 @@ +LOCAL_DIR := $(GET_LOCAL_DIR) + +MODULE := $(LOCAL_DIR) + +MODULE_SRCS += \ + $(LOCAL_DIR)/test_ubsan.c \ + $(LOCAL_DIR)/test_ubsan.cpp + +MODULE_DEPS += \ + lib/ubsan + +MODULE_COMPILEFLAGS += -fsanitize=undefined + +include make/module.mk diff --git a/lib/test_ubsan/test_ubsan.c b/lib/test_ubsan/test_ubsan.c new file mode 100644 index 0000000000..374b4c0786 --- /dev/null +++ b/lib/test_ubsan/test_ubsan.c @@ -0,0 +1,296 @@ +// Copyright 2024, Google LLC + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TESTCASE_UBSAN(x) { .func = x, .name = #x } + +typedef void (*test_ubsan_fp)(void); +struct test_ubsan_struct { + test_ubsan_fp func; + const char *const name; +}; + +static void add_overflow(void) { + volatile int val = INT_MAX; + volatile int val2 = 1; + + val += val2; +} + +static void sub_overflow(void) { + volatile int val = INT_MIN; + volatile int val2 = 1; + + val -= val2; +} + +static void mul_overflow(void) { + volatile int val = INT_MAX / 2; + volatile int val2 = 3; + + val *= val2; +} + +static void negate_overflow(void) { + volatile int val = INT_MIN; + + val = -val; +} + +static void divrem_overflow(void) { + volatile int val = 16; + volatile int val2 = 0; + + val /= val2; +} + +static void pointer_overflow(void) { + volatile uintptr_t offset = UINTPTR_MAX; + char buf[4]; + char *ptr = buf; + + ptr += offset; + (void) ptr; +} + +static void float_cast_overflow(void) { + volatile uint32_t val; + volatile uint32_t mul = 10; + + val = mul * 0xFFFF * 1e9; + (void) val; +} + +static void shift_out_of_bounds_overflow(void) { + volatile int pos = 1; + volatile int val = INT_MAX; + + val <<= pos; +} + +static void shift_out_of_bounds_negative(void) { + volatile int neg = -1; + volatile int val = 10; + + val <<= neg; +} + +static void out_of_bounds_overflow(void) { + volatile int val = 10; + volatile int overflow = 4; + volatile char above[4] = {}; + volatile int arr[4]; + volatile char below[4] = {}; + + above[0] = below[0]; + arr[overflow] = val; +} + +static void out_of_bounds_underflow(void) { + volatile int val = 10; + volatile int underflow = -1; + volatile char above[4] = {}; + volatile int arr[4]; + volatile char below[4] = {}; + + above[0] = below[0]; + arr[underflow] = val; +} + +static void load_invalid_value_bool(void) { + volatile char *dst, *src; + bool val, val2; + volatile char invalid_val = 2; + + src = &invalid_val; + dst = (char *)&val; + *dst = *src; + + val2 = val; + (void) val2; +} + +extern void load_invalid_value_enum(void); + +static void nullptr_deref(void) { + int *nullptr = NULL; + int val = *nullptr; + (void) val; +} + +static void misaligned_access(void) { + struct object { + int val; + }; + char buf[3]; + struct object *obj = (struct object *)buf; + + obj = (struct object*)(buf + 1); + obj->val = 0; +} + +static void object_size_mismatch(void) { + struct object { + int val; + }; + + char buf[3]; + struct object *obj = (struct object *)buf; + + obj->val = 0; +} + +static void func(int a) { return; } +static void function_type_mismatch(void) { + typedef void (*func_ptr)(void); + func_ptr f = (func_ptr) func; + f(); +} + +__attribute__((nonnull)) static void _nonnull_arg( void *ptr) { (void) ptr; } +static void nonnull_arg(void) { + volatile void *nullptr = NULL; + _nonnull_arg((void *)nullptr); +} + +__attribute__((returns_nonnull)) static void* _nonnull_return(void) { + volatile void *ret = NULL; + return (void *)ret; +} + +static void nonnull_return(void) { + _nonnull_return(); +} + +static void vla_bound_not_positive(void) { + volatile int size = 0; + int arr[size]; + + (void) arr; +} + +static void *_alignment_assumption(void) __attribute__((__assume_aligned__(32))); +static void *_alignment_assumption(void) { + volatile void *ptr = (void *)0x3; + return (void *)ptr; +} + +static void *_alignment_assumption_offset(void) __attribute__((__assume_aligned__(32, 4))); +static void *_alignment_assumption_offset(void) { + volatile void *ptr = (void *)0x3; + return (void *)ptr; +} + +static void alignment_assumption(void) { + void *ptr; + + ptr = _alignment_assumption(); + (void) ptr; +} + +static void alignment_assumption_offset(void) { + void *ptr; + + ptr = _alignment_assumption_offset(); + (void) ptr; +} + +// __builtin_clzg and __builtin_ctzg is not support +static void invalid_builtin_clz(void) { + int ret = __builtin_clz(0); + (void) ret; +} + +static void invalid_builtin_ctz(void) { + int ret = __builtin_ctz(0); + (void) ret; +} + +static void builtin_unreachable(void) { + __UNREACHABLE; +} + +static const struct test_ubsan_struct test_ubsan_array[] = { + TESTCASE_UBSAN(add_overflow), + TESTCASE_UBSAN(sub_overflow), + TESTCASE_UBSAN(mul_overflow), + TESTCASE_UBSAN(negate_overflow), + TESTCASE_UBSAN(pointer_overflow), + TESTCASE_UBSAN(float_cast_overflow), + TESTCASE_UBSAN(shift_out_of_bounds_overflow), + TESTCASE_UBSAN(shift_out_of_bounds_negative), + TESTCASE_UBSAN(out_of_bounds_overflow), + TESTCASE_UBSAN(out_of_bounds_underflow), + TESTCASE_UBSAN(load_invalid_value_bool), + TESTCASE_UBSAN(load_invalid_value_enum), + TESTCASE_UBSAN(nullptr_deref), + TESTCASE_UBSAN(misaligned_access), + TESTCASE_UBSAN(object_size_mismatch), + TESTCASE_UBSAN(function_type_mismatch), + TESTCASE_UBSAN(nonnull_arg), + TESTCASE_UBSAN(nonnull_return), + TESTCASE_UBSAN(vla_bound_not_positive), + TESTCASE_UBSAN(alignment_assumption), + TESTCASE_UBSAN(alignment_assumption_offset), + TESTCASE_UBSAN(invalid_builtin_clz), + TESTCASE_UBSAN(invalid_builtin_ctz), + TESTCASE_UBSAN(builtin_unreachable), +}; + + +static void show_usage(void) { + printf("Usage: test_ubsan [OPTION]\n"); + printf(" NUM - The testcase number you want to test\n"); + printf(" all - executing all ubsan test cases\n"); + printf("Available ubsan test cases:\n"); + printf("Num: testcase name\n"); + for (unsigned int i = 0; i < ARRAY_SIZE(test_ubsan_array); ++i) + printf("%3u: %s\n", i, test_ubsan_array[i].name); +} + +static int test_ubsan(int argc, const console_cmd_args *argv) { + + unsigned long id; + + if (argc != 2) { + show_usage(); + return argc == 1 ? NO_ERROR : ERR_INVALID_ARGS; + } + + if (!strcmp(argv[1].str, "all")) { + for (unsigned int i = 0; i < ARRAY_SIZE(test_ubsan_array); ++i) { + printf("start %s ...\n", test_ubsan_array[i].name); + test_ubsan_array[i].func(); + } + + return NO_ERROR; + } + + if (!isdigit(argv[1].str[0])) { + show_usage(); + return ERR_INVALID_ARGS; + } + + id = argv[1].u; + + if (id >= ARRAY_SIZE(test_ubsan_array)) { + show_usage(); + return ERR_INVALID_ARGS; + } + + printf("start %s ...\n", test_ubsan_array[id].name); + test_ubsan_array[id].func(); + return NO_ERROR; +} + +STATIC_COMMAND_START +STATIC_COMMAND("test_ubsan", "testing ubsan", test_ubsan) +STATIC_COMMAND_END(test_ubsan); diff --git a/lib/test_ubsan/test_ubsan.cpp b/lib/test_ubsan/test_ubsan.cpp new file mode 100644 index 0000000000..73ef63e4b7 --- /dev/null +++ b/lib/test_ubsan/test_ubsan.cpp @@ -0,0 +1,13 @@ +extern "C" +{ + +// https://cplusplus.github.io/CWG/issues/1766.html +// It is only since C++17 that loading an out-of-range value for an enum is undefined behavior. +// But clang treats this as UB even with C++14(LK compiles C++ files with --std=c++14 by default) +void load_invalid_value_enum(void) { + enum E {e1, e2, e3, e4}; + volatile int a = 5; + volatile enum E e = *((volatile enum E*)(&a)); + (void) &e; +} +}