* [PATCH] tools/nolibc: make __nolibc_enosys() a compile time error
@ 2026-04-04 15:26 Thomas Weißschuh
2026-04-07 7:15 ` Willy Tarreau
0 siblings, 1 reply; 3+ messages in thread
From: Thomas Weißschuh @ 2026-04-04 15:26 UTC (permalink / raw)
To: Willy Tarreau; +Cc: linux-kernel, Thomas Weißschuh
Functions which are known at compile-time to result in ENOSYS can be
surprising to the user. For example using old UAPI headers might mean
that stat() will always fail although the kernel would have the system
call available at runtime. Nowadays __nolibc_enosys() should never be
called for normal applications.
Switch the silent ENOSYS return into a compile-time error, so the user
is aware about the issue. Prefer the 'error' attribute as it provides
the best diagnostics. If the users defines NOLIBC_COMPILE_TIME_ENOSYS
the old, silent fallback is kept.
Also add a test which validates that the error can be optimized away.
Reported-by: Willy Tarreau <w@1wt.eu>
Closes: https://lore.kernel.org/lkml/acizRIq2xrFUNHNS@1wt.eu/
Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
---
This should probably go into the next cycle.
---
tools/include/nolibc/sys.h | 18 ++++++++++++++++--
tools/testing/selftests/nolibc/nolibc-test.c | 18 ++++++++++++++++++
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
index 6335fd51f07f..fd7a2ee780e8 100644
--- a/tools/include/nolibc/sys.h
+++ b/tools/include/nolibc/sys.h
@@ -45,16 +45,30 @@
: __sysret_arg; /* return original value */ \
})
-/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
- * debugging hook.
+/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
+ * time validation and a debugging hook.
*/
+#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
static __inline__ int __nolibc_enosys(const char *syscall, ...)
{
(void)syscall;
return -ENOSYS;
}
+#elif __nolibc_has_attribute(error)
+__attribute__((error("system call not implemented")))
+extern int __nolibc_enosys(const char *syscall, ...);
+
+#else
+static __inline__ int __nolibc_enosys(const char *syscall, ...)
+{
+ extern int __nolibc_enosys_error;
+ (void)syscall;
+
+ return __nolibc_enosys_error;
+}
+#endif
/* Functions in this file only describe syscalls. They're declared static so
* that the compiler usually decides to inline them while still being allowed
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index dd10402267ee..fb7eaa26ca93 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -1300,6 +1300,23 @@ int test_openat(void)
return 0;
}
+int test_nolibc_enosys(void)
+{
+ if (true)
+ return 0;
+
+#if defined(NOLIBC)
+ /*
+ * __nolibc_enosys() will fail the compilation.
+ * Make sure it can be optimized away if not actually called.
+ */
+ if (__nolibc_enosys("something") != -ENOSYS)
+ return 1;
+#endif
+
+ return 0;
+}
+
int test_namespace(void)
{
int original_ns, new_ns, ret;
@@ -1468,6 +1485,7 @@ int run_syscall(int min, int max)
CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap(NULL, 0), -1, EINVAL); break;
CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break;
CASE_TEST(nanosleep); ts.tv_nsec = -1; EXPECT_SYSER(1, nanosleep(&ts, NULL), -1, EINVAL); break;
+ CASE_TEST(nolibc_enosys); EXPECT_ZR(is_nolibc, test_nolibc_enosys()); break;
CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", O_RDONLY), -1); if (tmp != -1) close(tmp); break;
CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", O_RDONLY), -1, ENOENT); if (tmp != -1) close(tmp); break;
CASE_TEST(openat_dir); EXPECT_SYSZR(1, test_openat()); break;
---
base-commit: 74986b90eaf3f0ec38bd54de4851063616b49486
change-id: 20260404-nolibc-enosys-d601cc75ab29
Best regards,
--
Thomas Weißschuh <linux@weissschuh.net>
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] tools/nolibc: make __nolibc_enosys() a compile time error
2026-04-04 15:26 [PATCH] tools/nolibc: make __nolibc_enosys() a compile time error Thomas Weißschuh
@ 2026-04-07 7:15 ` Willy Tarreau
2026-04-07 11:02 ` David Laight
0 siblings, 1 reply; 3+ messages in thread
From: Willy Tarreau @ 2026-04-07 7:15 UTC (permalink / raw)
To: Thomas Weißschuh; +Cc: linux-kernel
Hi Thomas,
On Sat, Apr 04, 2026 at 05:26:05PM +0200, Thomas Weißschuh wrote:
> Functions which are known at compile-time to result in ENOSYS can be
> surprising to the user. For example using old UAPI headers might mean
> that stat() will always fail although the kernel would have the system
> call available at runtime. Nowadays __nolibc_enosys() should never be
> called for normal applications.
>
> Switch the silent ENOSYS return into a compile-time error, so the user
> is aware about the issue. Prefer the 'error' attribute as it provides
> the best diagnostics. If the users defines NOLIBC_COMPILE_TIME_ENOSYS
> the old, silent fallback is kept.
>
> Also add a test which validates that the error can be optimized away.
>
> Reported-by: Willy Tarreau <w@1wt.eu>
> Closes: https://lore.kernel.org/lkml/acizRIq2xrFUNHNS@1wt.eu/
> Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> ---
> This should probably go into the next cycle.
> ---
> tools/include/nolibc/sys.h | 18 ++++++++++++++++--
> tools/testing/selftests/nolibc/nolibc-test.c | 18 ++++++++++++++++++
> 2 files changed, 34 insertions(+), 2 deletions(-)
>
> diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
> index 6335fd51f07f..fd7a2ee780e8 100644
> --- a/tools/include/nolibc/sys.h
> +++ b/tools/include/nolibc/sys.h
> @@ -45,16 +45,30 @@
> : __sysret_arg; /* return original value */ \
> })
>
> -/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
> - * debugging hook.
> +/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
> + * time validation and a debugging hook.
> */
>
> +#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
> static __inline__ int __nolibc_enosys(const char *syscall, ...)
> {
> (void)syscall;
> return -ENOSYS;
> }
>
> +#elif __nolibc_has_attribute(error)
> +__attribute__((error("system call not implemented")))
> +extern int __nolibc_enosys(const char *syscall, ...);
I didn't know it was possible to force the error message like this,
I like it!
> +#else
> +static __inline__ int __nolibc_enosys(const char *syscall, ...)
> +{
> + extern int __nolibc_enosys_error;
> + (void)syscall;
> +
> + return __nolibc_enosys_error;
> +}
> +#endif
>
> /* Functions in this file only describe syscalls. They're declared static so
> * that the compiler usually decides to inline them while still being allowed
> diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
> index dd10402267ee..fb7eaa26ca93 100644
> --- a/tools/testing/selftests/nolibc/nolibc-test.c
> +++ b/tools/testing/selftests/nolibc/nolibc-test.c
> @@ -1300,6 +1300,23 @@ int test_openat(void)
> return 0;
> }
>
> +int test_nolibc_enosys(void)
> +{
> + if (true)
> + return 0;
> +
> +#if defined(NOLIBC)
> + /*
> + * __nolibc_enosys() will fail the compilation.
> + * Make sure it can be optimized away if not actually called.
> + */
> + if (__nolibc_enosys("something") != -ENOSYS)
> + return 1;
> +#endif
> +
> + return 0;
> +}
> +
> int test_namespace(void)
> {
> int original_ns, new_ns, ret;
> @@ -1468,6 +1485,7 @@ int run_syscall(int min, int max)
> CASE_TEST(munmap_bad); EXPECT_SYSER(1, munmap(NULL, 0), -1, EINVAL); break;
> CASE_TEST(mmap_munmap_good); EXPECT_SYSZR(1, test_mmap_munmap()); break;
> CASE_TEST(nanosleep); ts.tv_nsec = -1; EXPECT_SYSER(1, nanosleep(&ts, NULL), -1, EINVAL); break;
> + CASE_TEST(nolibc_enosys); EXPECT_ZR(is_nolibc, test_nolibc_enosys()); break;
> CASE_TEST(open_tty); EXPECT_SYSNE(1, tmp = open("/dev/null", O_RDONLY), -1); if (tmp != -1) close(tmp); break;
> CASE_TEST(open_blah); EXPECT_SYSER(1, tmp = open("/proc/self/blah", O_RDONLY), -1, ENOENT); if (tmp != -1) close(tmp); break;
> CASE_TEST(openat_dir); EXPECT_SYSZR(1, test_openat()); break;
>
> ---
> base-commit: 74986b90eaf3f0ec38bd54de4851063616b49486
> change-id: 20260404-nolibc-enosys-d601cc75ab29
>
> Best regards,
> --
> Thomas Weißschuh <linux@weissschuh.net>
Acked-by: Willy Tarreau <w@1wt.eu>
Thanks!
Willy
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] tools/nolibc: make __nolibc_enosys() a compile time error
2026-04-07 7:15 ` Willy Tarreau
@ 2026-04-07 11:02 ` David Laight
0 siblings, 0 replies; 3+ messages in thread
From: David Laight @ 2026-04-07 11:02 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel
On Tue, 7 Apr 2026 09:15:28 +0200
Willy Tarreau <w@1wt.eu> wrote:
> Hi Thomas,
>
> On Sat, Apr 04, 2026 at 05:26:05PM +0200, Thomas Weißschuh wrote:
> > Functions which are known at compile-time to result in ENOSYS can be
> > surprising to the user. For example using old UAPI headers might mean
> > that stat() will always fail although the kernel would have the system
> > call available at runtime. Nowadays __nolibc_enosys() should never be
> > called for normal applications.
> >
> > Switch the silent ENOSYS return into a compile-time error, so the user
> > is aware about the issue. Prefer the 'error' attribute as it provides
> > the best diagnostics. If the users defines NOLIBC_COMPILE_TIME_ENOSYS
> > the old, silent fallback is kept.
> >
> > Also add a test which validates that the error can be optimized away.
> >
> > Reported-by: Willy Tarreau <w@1wt.eu>
> > Closes: https://lore.kernel.org/lkml/acizRIq2xrFUNHNS@1wt.eu/
> > Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>
> > ---
> > This should probably go into the next cycle.
> > ---
> > tools/include/nolibc/sys.h | 18 ++++++++++++++++--
> > tools/testing/selftests/nolibc/nolibc-test.c | 18 ++++++++++++++++++
> > 2 files changed, 34 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/include/nolibc/sys.h b/tools/include/nolibc/sys.h
> > index 6335fd51f07f..fd7a2ee780e8 100644
> > --- a/tools/include/nolibc/sys.h
> > +++ b/tools/include/nolibc/sys.h
> > @@ -45,16 +45,30 @@
> > : __sysret_arg; /* return original value */ \
> > })
> >
> > -/* Syscall ENOSYS helper: Avoids unused-parameter warnings and provides a
> > - * debugging hook.
> > +/* Syscall ENOSYS helper: Avoids unused-parameter warnings, provides compile
> > + * time validation and a debugging hook.
> > */
> >
> > +#if defined(NOLIBC_COMPILE_TIME_ENOSYS)
> > static __inline__ int __nolibc_enosys(const char *syscall, ...)
> > {
> > (void)syscall;
> > return -ENOSYS;
> > }
> >
> > +#elif __nolibc_has_attribute(error)
> > +__attribute__((error("system call not implemented")))
> > +extern int __nolibc_enosys(const char *syscall, ...);
>
> I didn't know it was possible to force the error message like this,
> I like it!
Look at __compiletime_assert() in include/linux/compiler_types.h
If you try a bit harder it should be possible to get the system call
name into the error message.
Perhaps something like:
#define __nolibc__enosys(syscall, name, ...) ({ \
void __nolibc_enosys_##name(...) __attribute__((error("system call " #name " not implemented"))); \
__nolibc_enosys_##name(__VA_ARGS__); \
-ENOSYS; \
})
David
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-04-07 11:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-04 15:26 [PATCH] tools/nolibc: make __nolibc_enosys() a compile time error Thomas Weißschuh
2026-04-07 7:15 ` Willy Tarreau
2026-04-07 11:02 ` David Laight
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox