Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-) --- base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Certain compiler features are signaled via the __has_feature() preprocessor builtin.
Add a nolibc wrapper for it, similar to __nolibc_has_attribute().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/compiler.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/tools/include/nolibc/compiler.h b/tools/include/nolibc/compiler.h index fa1f547e7f13d151ea98b9c585b36659d2d27324..e6d6dc116e43aa69b37eca02ed1590fc09486bdb 100644 --- a/tools/include/nolibc/compiler.h +++ b/tools/include/nolibc/compiler.h @@ -12,6 +12,12 @@ # define __nolibc_has_attribute(attr) 0 #endif
+#if defined(__has_feature) +# define __nolibc_has_feature(feature) __has_feature(feature) +#else +# define __nolibc_has_feature(feature) 0 +#endif + #if __nolibc_has_attribute(naked) # define __nolibc_entrypoint __attribute__((naked)) # define __nolibc_entrypoint_epilogue()
Both constructors and main() may be executed with different function signatures than they are actually using. This is intentional but trips up UBSAN.
Disable the function sanitizer of UBSAN in _start_c().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/crt.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index c4b10103bbec50f1a3a0a4562e34fdbd1b43ce6f..961cfe777c3564e705dfdd581de828b374d05b0b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H
+#include "compiler.h" + char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak));
@@ -25,6 +27,9 @@ extern void (*const __fini_array_end[])(void) __attribute__((weak));
void _start_c(long *sp); __attribute__((weak,used)) +#if __nolibc_has_feature(undefined_behavior_sanitizer) + __attribute__((no_sanitize("function"))) +#endif void _start_c(long *sp) { long argc;
On Wed, Apr 16, 2025 at 08:40:17PM +0200, Thomas Weißschuh wrote:
Both constructors and main() may be executed with different function signatures than they are actually using. This is intentional but trips up UBSAN.
Disable the function sanitizer of UBSAN in _start_c().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/crt.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index c4b10103bbec50f1a3a0a4562e34fdbd1b43ce6f..961cfe777c3564e705dfdd581de828b374d05b0b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H +#include "compiler.h"
char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); @@ -25,6 +27,9 @@ extern void (*const __fini_array_end[])(void) __attribute__((weak)); void _start_c(long *sp); __attribute__((weak,used)) +#if __nolibc_has_feature(undefined_behavior_sanitizer)
- __attribute__((no_sanitize("function")))
+#endif
I'm wondering if it wouldn't be more reliable with:
#if __nolibc_has_attribute(no_sanitize) __attribute__((no_sanitize("function"))) #endif
Because in the end, what you want is to always place that attribute whenever it's supported, no ?
void _start_c(long *sp) { long argc;
Willy
On 2025-04-19 11:06:31+0200, Willy Tarreau wrote:
On Wed, Apr 16, 2025 at 08:40:17PM +0200, Thomas Weißschuh wrote:
Both constructors and main() may be executed with different function signatures than they are actually using. This is intentional but trips up UBSAN.
Disable the function sanitizer of UBSAN in _start_c().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/crt.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index c4b10103bbec50f1a3a0a4562e34fdbd1b43ce6f..961cfe777c3564e705dfdd581de828b374d05b0b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H +#include "compiler.h"
char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); @@ -25,6 +27,9 @@ extern void (*const __fini_array_end[])(void) __attribute__((weak)); void _start_c(long *sp); __attribute__((weak,used)) +#if __nolibc_has_feature(undefined_behavior_sanitizer)
- __attribute__((no_sanitize("function")))
+#endif
I'm wondering if it wouldn't be more reliable with:
#if __nolibc_has_attribute(no_sanitize) __attribute__((no_sanitize("function"))) #endif
Because in the end, what you want is to always place that attribute whenever it's supported, no ?
That doesn't work because GCC does knows no_sanitize but not no_sanitize("function"). Also no_sanitize is not specific to UBSAN but works for all sanitizers.
void _start_c(long *sp) { long argc;
Willy
On Sat, Apr 19, 2025 at 12:10:24PM +0200, Thomas Weißschuh wrote:
On 2025-04-19 11:06:31+0200, Willy Tarreau wrote:
On Wed, Apr 16, 2025 at 08:40:17PM +0200, Thomas Weißschuh wrote:
Both constructors and main() may be executed with different function signatures than they are actually using. This is intentional but trips up UBSAN.
Disable the function sanitizer of UBSAN in _start_c().
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
tools/include/nolibc/crt.h | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/tools/include/nolibc/crt.h b/tools/include/nolibc/crt.h index c4b10103bbec50f1a3a0a4562e34fdbd1b43ce6f..961cfe777c3564e705dfdd581de828b374d05b0b 100644 --- a/tools/include/nolibc/crt.h +++ b/tools/include/nolibc/crt.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_CRT_H #define _NOLIBC_CRT_H +#include "compiler.h"
char **environ __attribute__((weak)); const unsigned long *_auxv __attribute__((weak)); @@ -25,6 +27,9 @@ extern void (*const __fini_array_end[])(void) __attribute__((weak)); void _start_c(long *sp); __attribute__((weak,used)) +#if __nolibc_has_feature(undefined_behavior_sanitizer)
- __attribute__((no_sanitize("function")))
+#endif
I'm wondering if it wouldn't be more reliable with:
#if __nolibc_has_attribute(no_sanitize) __attribute__((no_sanitize("function"))) #endif
Because in the end, what you want is to always place that attribute whenever it's supported, no ?
That doesn't work because GCC does knows no_sanitize but not no_sanitize("function"). Also no_sanitize is not specific to UBSAN but works for all sanitizers.
OK, thanks for explaining!
Willy
As byte buffer is overlaid with a 'struct dirent64'. it has to satisfy the structs alignment requirements.
Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/dirent.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/include/nolibc/dirent.h b/tools/include/nolibc/dirent.h index c5c30d0dd6806b1bec2fa8120a3df29aaa201393..cd0ddff86c360b14913a809c8696d89d8a356e9e 100644 --- a/tools/include/nolibc/dirent.h +++ b/tools/include/nolibc/dirent.h @@ -58,6 +58,7 @@ int closedir(DIR *dirp) static __attribute__((unused)) int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { + __attribute__((aligned(__alignof__(struct linux_dirent64)))) char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1]; struct linux_dirent64 *ldir = (void *)buf; intptr_t i = (intptr_t)dirp;
On Wed, Apr 16, 2025 at 08:40:18PM +0200, Thomas Weißschuh wrote:
As byte buffer is overlaid with a 'struct dirent64'. it has to satisfy the structs alignment requirements.
Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Oh good catch! I already faced crashes in other programs due to AVX memcpy when doing similar casts without thinking about alignment.
@@ -58,6 +58,7 @@ int closedir(DIR *dirp) static __attribute__((unused)) int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
- __attribute__((aligned(__alignof__(struct linux_dirent64)))) char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1];
I tend to find it more readable when the attribute is on the same line as the type on variables declaration, often at the end of the line, to keep declarations alignes, even if that makes longer lines. If alignment concerns come back often, we could maybe have __nolibc_align(<align>) and maybe even __nolibc_align_as(<type>) to slightly shorten the lines. Just an idea.
In any case: Acked-by: Willy Tarreau w@1wt.eu
Willy
On 2025-04-19 11:11:40+0200, Willy Tarreau wrote:
On Wed, Apr 16, 2025 at 08:40:18PM +0200, Thomas Weißschuh wrote:
As byte buffer is overlaid with a 'struct dirent64'. it has to satisfy the structs alignment requirements.
Fixes: 665fa8dea90d ("tools/nolibc: add support for directory access") Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Oh good catch! I already faced crashes in other programs due to AVX memcpy when doing similar casts without thinking about alignment.
@@ -58,6 +58,7 @@ int closedir(DIR *dirp) static __attribute__((unused)) int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) {
- __attribute__((aligned(__alignof__(struct linux_dirent64)))) char buf[sizeof(struct linux_dirent64) + NAME_MAX + 1];
I tend to find it more readable when the attribute is on the same line as the type on variables declaration, often at the end of the line, to keep declarations alignes, even if that makes longer lines. If alignment concerns come back often, we could maybe have __nolibc_align(<align>) and maybe even __nolibc_align_as(<type>) to slightly shorten the lines. Just an idea.
Sounds good, the attribute soup is annoying.
In any case: Acked-by: Willy Tarreau w@1wt.eu
Thanks!
Thomas
In twos complement the most negative number can not be negated.
Fixes: b1c21e7d99cd ("tools/nolibc/stdlib: add i64toa() and u64toa()") Fixes: 66c397c4d2e1 ("tools/nolibc/stdlib: replace the ltoa() function with more efficient ones") Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/include/nolibc/stdlib.h | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-)
diff --git a/tools/include/nolibc/stdlib.h b/tools/include/nolibc/stdlib.h index 86ad378ab1ea220559d5ab1adc4bb9972977ba9e..5e4b97810d49ac1b1bd79d6f779f6a748f188a39 100644 --- a/tools/include/nolibc/stdlib.h +++ b/tools/include/nolibc/stdlib.h @@ -271,16 +271,12 @@ int utoa_r(unsigned long in, char *buffer) static __attribute__((unused)) int itoa_r(long in, char *buffer) { - char *ptr = buffer; - int len = 0; - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; + *(buffer++) = '-'; + return 1 + utoa_r(-(unsigned long)in, buffer); } - len += utoa_r(in, ptr); - return len; + + return utoa_r(in, buffer); }
/* for historical compatibility, same as above but returns the pointer to the @@ -407,16 +403,12 @@ int u64toa_r(uint64_t in, char *buffer) static __attribute__((unused)) int i64toa_r(int64_t in, char *buffer) { - char *ptr = buffer; - int len = 0; - if (in < 0) { - in = -in; - *(ptr++) = '-'; - len++; + *(buffer++) = '-'; + return 1 + u64toa_r(-(unsigned long long)in, buffer); } - len += u64toa_r(in, ptr); - return len; + + return u64toa_r(in, buffer); }
/* converts int64_t <in> to a string using the static itoa_buffer and returns
On Wed, Apr 16, 2025 at 08:40:19PM +0200, Thomas Weißschuh wrote:
In twos complement the most negative number can not be negated.
well, if we're picky, that's not really an int overflow since it's only used as an unsigned in the end, so -2^(N-1) == 2^(N-1) in twos complement.
@@ -271,16 +271,12 @@ int utoa_r(unsigned long in, char *buffer) static __attribute__((unused)) int itoa_r(long in, char *buffer) {
- char *ptr = buffer;
- int len = 0;
- if (in < 0) {
in = -in;
*(ptr++) = '-';
len++;
*(buffer++) = '-';
}return 1 + utoa_r(-(unsigned long)in, buffer);
- len += utoa_r(in, ptr);
- return len;
- return utoa_r(in, buffer);
}
At -Os it's OK but at -O2 it inflates it a little bit and at -O3 it significantly inflates the function (175 -> 320 bytes) due to the two calls that get inlined. Have you tried to check if ubsan is happy with just this?
- in = -in; + in = -(unsigned long)in;
Otherwise this variant doesn't inflate it for me and keeps the spirit of the original one (i.e. single call):
int itoa_r3(long in, char *buffer) { unsigned long uin = in; int len = 0;
if ((long)uin < 0) { uin = -uin; *(buffer++) = '-'; len++; } len += utoa_r(uin, buffer); return len; }
I'm also seeing a way to make it even smaller than the original by changing utoa_r() so that it takes the original buffer in a 3rd argument and emits the difference at the end as the length. This allows to always perform a tail call, though I'm not sure we really need it.
Thanks, Willy
On 2025-04-19 11:40:08+0200, Willy Tarreau wrote:
On Wed, Apr 16, 2025 at 08:40:19PM +0200, Thomas Weißschuh wrote:
In twos complement the most negative number can not be negated.
well, if we're picky, that's not really an int overflow since it's only used as an unsigned in the end, so -2^(N-1) == 2^(N-1) in twos complement.
It is used as unsigned, but at the point of the cast it's still signed. From ccpreference:
The unary minus invokes undefined behavior due to signed integer overflow when applied to INT_MIN, LONG_MIN, or LLONG_MIN, on typical (2's complement) platforms.
https://en.cppreference.com/w/c/language/operator_arithmetic
@@ -271,16 +271,12 @@ int utoa_r(unsigned long in, char *buffer) static __attribute__((unused)) int itoa_r(long in, char *buffer) {
- char *ptr = buffer;
- int len = 0;
- if (in < 0) {
in = -in;
*(ptr++) = '-';
len++;
*(buffer++) = '-';
}return 1 + utoa_r(-(unsigned long)in, buffer);
- len += utoa_r(in, ptr);
- return len;
- return utoa_r(in, buffer);
}
At -Os it's OK but at -O2 it inflates it a little bit and at -O3 it significantly inflates the function (175 -> 320 bytes) due to the two calls that get inlined. Have you tried to check if ubsan is happy with just this?
in = -in;
in = -(unsigned long)in;
That seems to work. Let's use it.
Thanks!
Otherwise this variant doesn't inflate it for me and keeps the spirit of the original one (i.e. single call):
int itoa_r3(long in, char *buffer) { unsigned long uin = in; int len = 0;
if ((long)uin < 0) { uin = -uin; *(buffer++) = '-'; len++; } len += utoa_r(uin, buffer); return len;
}
I'm also seeing a way to make it even smaller than the original by changing utoa_r() so that it takes the original buffer in a 3rd argument and emits the difference at the end as the length. This allows to always perform a tail call, though I'm not sure we really need it.
Thomas
smash_stack() intentionally crashes.
Prevent UBSAN from tripping over it.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c index 7a60b6ac1457e8d862ab1a6a26c9e46abec92111..b176a706609b7641dd1d743c8a02b6b6e7a4c746 100644 --- a/tools/testing/selftests/nolibc/nolibc-test.c +++ b/tools/testing/selftests/nolibc/nolibc-test.c @@ -1438,6 +1438,7 @@ static int run_vfprintf(int min, int max) return ret; }
+__attribute__((no_sanitize("undefined"))) static int smash_stack(void) { char buf[100];
UBSAN detects undefined behaviour at runtime. To avoid introduction of new UB, enable UBSAN for nolibc-test.
By signalling detected errors through traps no runtime dependency is necessary.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net --- tools/testing/selftests/nolibc/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/nolibc/Makefile b/tools/testing/selftests/nolibc/Makefile index aa05c1faac20d3054b231090b939d050b0231d40..94f3e8be7a68f63ecd639c4f283b3cd10764ce74 100644 --- a/tools/testing/selftests/nolibc/Makefile +++ b/tools/testing/selftests/nolibc/Makefile @@ -189,9 +189,10 @@ ifeq ($(origin XARCH),command line) CFLAGS_XARCH = $(CFLAGS_$(XARCH)) endif CFLAGS_STACKPROTECTOR ?= $(call cc-option,-mstack-protector-guard=global $(call cc-option,-fstack-protector-all)) +CFLAGS_SANITIZER ?= $(call cc-option,-fsanitize=undefined -fsanitize-trap=all) CFLAGS ?= -Os -fno-ident -fno-asynchronous-unwind-tables -std=c89 -W -Wall -Wextra \ $(call cc-option,-fno-stack-protector) $(call cc-option,-Wmissing-prototypes) \ - $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_EXTRA) + $(CFLAGS_XARCH) $(CFLAGS_STACKPROTECTOR) $(CFLAGS_SANITIZER) $(CFLAGS_EXTRA) LDFLAGS :=
LIBGCC := -lgcc
On Wed, Apr 16, 2025 at 08:40:21PM +0200, Thomas Weißschuh wrote:
UBSAN detects undefined behaviour at runtime. To avoid introduction of new UB, enable UBSAN for nolibc-test.
By signalling detected errors through traps no runtime dependency is necessary.
Yeah that can be pretty useful, I agree it's a good idea.
Acked-by: Willy Tarreau w@1wt.eu
Thanks, Willy
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
Thanx, Paul
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
Hi Paul,
On 2025-04-18 10:32:27-0700, Paul E. McKenney wrote:
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
They are intended for v6.16 through the normal process.
Thomas
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
On Fri, Apr 18, 2025 at 11:20:29PM +0200, Thomas Weißschuh wrote:
Hi Paul,
On 2025-04-18 10:32:27-0700, Paul E. McKenney wrote:
On Wed, Apr 16, 2025 at 08:40:15PM +0200, Thomas Weißschuh wrote:
Fix some issues uncovered by UBSAN and enable UBSAN for nolibc-test to avoid regressions.
Signed-off-by: Thomas Weißschuh linux@weissschuh.net
Thank you, Thomas! Are these intended to go into the current v6.15 release, or are you instead thinking in terms of the v6.16 merge window? Either works for me, but left to myself, I would assume the v6.16 merge window. ;-)
They are intended for v6.16 through the normal process.
Sounds good, and thank you for the clarification. Plus good show on getting them out early. ;-)
Thanx, Paul
Thomas
Thomas Weißschuh (6): tools/nolibc: add __nolibc_has_feature() tools/nolibc: disable function sanitizer for _start_c() tools/nolibc: properly align dirent buffer tools/nolibc: fix integer overflow in i{64,}toa_r() and selftests/nolibc: disable ubsan for smash_stack() selftests/nolibc: enable UBSAN if available
tools/include/nolibc/compiler.h | 6 ++++++ tools/include/nolibc/crt.h | 5 +++++ tools/include/nolibc/dirent.h | 1 + tools/include/nolibc/stdlib.h | 24 ++++++++---------------- tools/testing/selftests/nolibc/Makefile | 3 ++- tools/testing/selftests/nolibc/nolibc-test.c | 1 + 6 files changed, 23 insertions(+), 17 deletions(-)
base-commit: 7c73c10b906778384843b9d3ac6c2224727bbf5c change-id: 20250416-nolibc-ubsan-028401698654
Best regards,
Thomas Weißschuh linux@weissschuh.net
linux-kselftest-mirror@lists.linaro.org