Fil-C [1] is a tool for running C and C++ programs in a memory-safe mode. Given a decent test suite coverage for a package, it can be used as an alternative to ASAN and (to some extent) valgrind.
But before you can use it with your packages that use Gnulib, Gnulib must be ported first :) The author of Fil-C noticed some test failures in Gnulib [2]. This set of patches ports the essential modules. There are still a couple of test failures. Namely, what does not work? - conversions from [u]intptr_t to a pointer - <fenv.h> glibc-specific functions - asm with pointer arguments - at-init [1] https://fil-c.org/ [2] https://fil-c.org/programs_that_work 2026-07-25 Bruno Haible <[email protected]> tests: Avoid some runtime errors with Fil-C. * tests/test-alignalloc.c (MAX_ALIGNMENT): New macro. Use it instead of 16 MiB. * tests/test-calloc-posix.c (main): Skip big allocations on Fil-C. * tests/test-calloc-gnu.c (main): Likewise. * tests/test-malloc-posix.c (main): Likewise. * tests/test-malloc-gnu.c (main): Likewise. * tests/test-realloc-posix.c (main): Likewise. * tests/test-reallocarray.c (main): Likewise. * tests/test-fprintf-posix2.c: Likewise. * tests/test-printf-posix2.c: Likewise. sigsegv: Port to Fil-C. * lib/sigsegv.in.h (HAVE_STACK_OVERFLOW_RECOVERY): Don't define with Fil-C. [v]szprintf: Port to Fil-C. * lib/szprintf.c (szprintf): Ensure lenbuf is at most INT_MAX. * lib/vszprintf.c (vszprintf): Likewise. * lib/unistdio/u-vsprintf.h (VSPRINTF): Ensure lenbuf is at most INT_MAX / sizeof (DCHAR_T). fpucw: Avoid runtime error with Fil-C. * lib/fpucw.h: Use no-op definitions with Fil-C. thread-optim: Avoid runtime error with Fil-C. * lib/thread-optim.h (_GL_MULTITHREADED_VIA_ELF): Don't define with Fil-C. isinf: Avoid compilation error with Fil-C. * lib/math.in.h (isinf): In C++ mode, don't define as a macro.
>From 888c325608b88b8664b893b1d800491227be56a7 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sat, 25 Jul 2026 16:16:30 +0200 Subject: [PATCH 1/6] isinf: Avoid compilation error with Fil-C. * lib/math.in.h (isinf): In C++ mode, don't define as a macro. --- ChangeLog | 5 +++++ lib/math.in.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 97ce480fd9..9c6d98b9ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2026-07-25 Bruno Haible <[email protected]> + + isinf: Avoid compilation error with Fil-C. + * lib/math.in.h (isinf): In C++ mode, don't define as a macro. + 2026-07-25 Paul Eggert <[email protected]> gettext-h: conform to C on Solaris diff --git a/lib/math.in.h b/lib/math.in.h index 89dfb9307d..b3ffab4e8b 100644 --- a/lib/math.in.h +++ b/lib/math.in.h @@ -2525,7 +2525,7 @@ template <> inline int isinf<long double> (long double x) { return _gl_isinfl (x # if defined isinf || defined GNULIB_NAMESPACE _GL_MATH_CXX_REAL_FLOATING_DECL_1 (isinf) # undef isinf -# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || (defined _WIN32 && !defined __CYGWIN__))) +# if __GNUC__ >= 6 || (defined __clang__ && !((defined __APPLE__ && defined __MACH__) || defined __FreeBSD__ || defined __OpenBSD__ || (defined _WIN32 && !defined __CYGWIN__) || defined __FILC__)) /* This platform's <cmath> possibly defines isinf through a set of inline functions. */ _GL_MATH_CXX_REAL_FLOATING_DECL_2 (isinf, rpl_isinf, bool) -- 2.53.0
>From 5e7a0aa66938138a5f724d5c18bb2a5f5c37c2e7 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sat, 25 Jul 2026 16:53:43 +0200 Subject: [PATCH 2/6] thread-optim: Avoid runtime error with Fil-C. * lib/thread-optim.h (_GL_MULTITHREADED_VIA_ELF): Don't define with Fil-C. --- ChangeLog | 3 +++ lib/thread-optim.h | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9c6d98b9ee..c01e6335dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2026-07-25 Bruno Haible <[email protected]> + thread-optim: Avoid runtime error with Fil-C. + * lib/thread-optim.h (_GL_MULTITHREADED_VIA_ELF): Don't define with Fil-C. + isinf: Avoid compilation error with Fil-C. * lib/math.in.h (isinf): In C++ mode, don't define as a macro. diff --git a/lib/thread-optim.h b/lib/thread-optim.h index e4c0e03f5e..dc097c8046 100644 --- a/lib/thread-optim.h +++ b/lib/thread-optim.h @@ -72,7 +72,8 @@ #elif defined __ELF__ /* Linux, Hurd, FreeBSD, NetBSD, OpenBSD, Solaris, ... */\ && HAVE_LINK_H \ - && HAVE_DL_ITERATE_PHDR /* not Solaris 10, not Haiku */ + && (HAVE_DL_ITERATE_PHDR /* not Solaris 10, not Haiku */ \ + && !defined __FILC__ /* not Fil-C */) /* We can detect whether pthread_create() can be invoked, by looking at the contents of the PLT of the executable and of each shared object. */ -- 2.53.0
>From c3a842f245d36716d93e7761875899d9ebb40e18 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sat, 25 Jul 2026 18:02:37 +0200 Subject: [PATCH 3/6] fpucw: Avoid runtime error with Fil-C. * lib/fpucw.h: Use no-op definitions with Fil-C. --- ChangeLog | 3 +++ lib/fpucw.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index c01e6335dd..1f7105dcc0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2026-07-25 Bruno Haible <[email protected]> + fpucw: Avoid runtime error with Fil-C. + * lib/fpucw.h: Use no-op definitions with Fil-C. + thread-optim: Avoid runtime error with Fil-C. * lib/thread-optim.h (_GL_MULTITHREADED_VIA_ELF): Don't define with Fil-C. diff --git a/lib/fpucw.h b/lib/fpucw.h index e80324a191..0eff69acc9 100644 --- a/lib/fpucw.h +++ b/lib/fpucw.h @@ -67,7 +67,7 @@ extern "C" { /* Inline assembler like this works only with GNU C and clang. */ -#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__ || defined __clang__) +#if (defined __i386__ || defined __x86_64__) && (defined __GNUC__ || defined __clang__) && !defined __FILC__ typedef unsigned short fpucw_t; /* glibc calls this fpu_control_t */ -- 2.53.0
>From 6fd0a1fa4c76b3fe3172f69a6f99babea3ce8dbc Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sun, 26 Jul 2026 01:15:14 +0200 Subject: [PATCH 4/6] szprintf: Port to Fil-C. * lib/szprintf.c (szprintf): Ensure lenbuf is at most INT_MAX. * lib/vszprintf.c (vszprintf): Likewise. * lib/unistdio/u-vsprintf.h (VSPRINTF): Ensure lenbuf is at most INT_MAX / sizeof (DCHAR_T). --- ChangeLog | 6 ++++++ lib/szprintf.c | 5 +++++ lib/unistdio/u-vsprintf.h | 4 ++++ lib/vszprintf.c | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1f7105dcc0..6a9b47c6a9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2026-07-25 Bruno Haible <[email protected]> + [v]szprintf: Port to Fil-C. + * lib/szprintf.c (szprintf): Ensure lenbuf is at most INT_MAX. + * lib/vszprintf.c (vszprintf): Likewise. + * lib/unistdio/u-vsprintf.h (VSPRINTF): Ensure lenbuf is at most + INT_MAX / sizeof (DCHAR_T). + fpucw: Avoid runtime error with Fil-C. * lib/fpucw.h: Use no-op definitions with Fil-C. diff --git a/lib/szprintf.c b/lib/szprintf.c index a5a3291c9e..651aae801e 100644 --- a/lib/szprintf.c +++ b/lib/szprintf.c @@ -22,6 +22,7 @@ #include <stdio.h> #include <errno.h> +#include <limits.h> #include <stdarg.h> #include <stdint.h> #include <stdlib.h> @@ -38,6 +39,10 @@ szprintf (char *str, const char *format, ...) size_t lenbuf = SIZE_MAX; if (lenbuf >= ~ (uintptr_t) str) lenbuf = ~ (uintptr_t) str; +#if defined __FILC__ + if (lenbuf > INT_MAX) + lenbuf = INT_MAX; +#endif char *output = vasnprintf (str, &lenbuf, format, args); size_t len = lenbuf; diff --git a/lib/unistdio/u-vsprintf.h b/lib/unistdio/u-vsprintf.h index 4cc7506b54..6f93257c17 100644 --- a/lib/unistdio/u-vsprintf.h +++ b/lib/unistdio/u-vsprintf.h @@ -39,6 +39,10 @@ VSPRINTF (DCHAR_T *buf, const FCHAR_T *format, va_list args) size_t length = (SIZE_MAX < INT_MAX ? SIZE_MAX : INT_MAX); if (length > (~ (uintptr_t) buf) / sizeof (DCHAR_T)) length = (~ (uintptr_t) buf) / sizeof (DCHAR_T); +#if defined __FILC__ + if (length > INT_MAX / sizeof (DCHAR_T)) + length = INT_MAX / sizeof (DCHAR_T); +#endif DCHAR_T *result = VASNPRINTF (buf, &length, format, args); if (result == NULL) diff --git a/lib/vszprintf.c b/lib/vszprintf.c index 69c6fa05bb..2a65064541 100644 --- a/lib/vszprintf.c +++ b/lib/vszprintf.c @@ -22,6 +22,7 @@ #include <stdio.h> #include <errno.h> +#include <limits.h> #include <stdarg.h> #include <stdint.h> #include <stdlib.h> @@ -35,6 +36,10 @@ vszprintf (char *str, const char *format, va_list args) size_t lenbuf = SIZE_MAX; if (lenbuf >= ~ (uintptr_t) str) lenbuf = ~ (uintptr_t) str; +#if defined __FILC__ + if (lenbuf > INT_MAX) + lenbuf = INT_MAX; +#endif char *output = vasnprintf (str, &lenbuf, format, args); size_t len = lenbuf; -- 2.53.0
>From 8a4de85590c21a51c66e0d4655ea62616fa2a12d Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sun, 26 Jul 2026 00:38:07 +0200 Subject: [PATCH 5/6] sigsegv: Port to Fil-C. * lib/sigsegv.in.h (HAVE_STACK_OVERFLOW_RECOVERY): Don't define with Fil-C. --- ChangeLog | 3 +++ lib/sigsegv.in.h | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6a9b47c6a9..3c73ace99e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2026-07-25 Bruno Haible <[email protected]> + sigsegv: Port to Fil-C. + * lib/sigsegv.in.h (HAVE_STACK_OVERFLOW_RECOVERY): Don't define with Fil-C. + [v]szprintf: Port to Fil-C. * lib/szprintf.c (szprintf): Ensure lenbuf is at most INT_MAX. * lib/vszprintf.c (vszprintf): Likewise. diff --git a/lib/sigsegv.in.h b/lib/sigsegv.in.h index b58d773e2d..499c54868f 100644 --- a/lib/sigsegv.in.h +++ b/lib/sigsegv.in.h @@ -77,13 +77,14 @@ /* HAVE_STACK_OVERFLOW_RECOVERY is defined if stack overflow can be caught. */ -#if defined __linux__ || defined __ANDROID__ || defined __gnu_hurd__ \ - || defined __FreeBSD_kernel__ || (defined __FreeBSD__ && !(defined __sparc__ || defined __sparc64__)) || defined __DragonFly__ \ - || (defined __NetBSD__ && !(defined __sparc__ || defined __sparc64__)) \ - || defined __OpenBSD__ \ - || (defined __APPLE__ && defined __MACH__) \ - || defined _AIX || defined __sun \ - || defined __CYGWIN__ || defined __HAIKU__ +#if (defined __linux__ || defined __ANDROID__ || defined __gnu_hurd__ \ + || defined __FreeBSD_kernel__ || (defined __FreeBSD__ && !(defined __sparc__ || defined __sparc64__)) || defined __DragonFly__ \ + || (defined __NetBSD__ && !(defined __sparc__ || defined __sparc64__)) \ + || defined __OpenBSD__ \ + || (defined __APPLE__ && defined __MACH__) \ + || defined _AIX || defined __sun \ + || defined __CYGWIN__ || defined __HAIKU__) \ + && !defined __FILC__ /* Linux, Hurd, GNU/kFreeBSD, FreeBSD, NetBSD, OpenBSD, macOS, AIX, Solaris, Cygwin, Haiku */ # define HAVE_STACK_OVERFLOW_RECOVERY 1 #endif -- 2.53.0
>From 8b8f9802dd1ed663977010411fabb4b5166116d6 Mon Sep 17 00:00:00 2001 From: Bruno Haible <[email protected]> Date: Sun, 26 Jul 2026 00:42:05 +0200 Subject: [PATCH 6/6] tests: Avoid some runtime errors with Fil-C. * tests/test-alignalloc.c (MAX_ALIGNMENT): New macro. Use it instead of 16 MiB. * tests/test-calloc-posix.c (main): Skip big allocations on Fil-C. * tests/test-calloc-gnu.c (main): Likewise. * tests/test-malloc-posix.c (main): Likewise. * tests/test-malloc-gnu.c (main): Likewise. * tests/test-realloc-posix.c (main): Likewise. * tests/test-reallocarray.c (main): Likewise. * tests/test-fprintf-posix2.c: Likewise. * tests/test-printf-posix2.c: Likewise. --- ChangeLog | 12 ++++++++++++ tests/test-alignalloc.c | 7 ++++++- tests/test-calloc-gnu.c | 6 +++++- tests/test-calloc-posix.c | 6 ++++++ tests/test-fprintf-posix2.c | 5 +++-- tests/test-malloc-gnu.c | 4 ++++ tests/test-malloc-posix.c | 6 ++++++ tests/test-printf-posix2.c | 5 +++-- tests/test-realloc-posix.c | 4 ++++ tests/test-reallocarray.c | 7 +++++++ 10 files changed, 56 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3c73ace99e..7a5d11b2c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2026-07-25 Bruno Haible <[email protected]> + tests: Avoid some runtime errors with Fil-C. + * tests/test-alignalloc.c (MAX_ALIGNMENT): New macro. Use it instead + of 16 MiB. + * tests/test-calloc-posix.c (main): Skip big allocations on Fil-C. + * tests/test-calloc-gnu.c (main): Likewise. + * tests/test-malloc-posix.c (main): Likewise. + * tests/test-malloc-gnu.c (main): Likewise. + * tests/test-realloc-posix.c (main): Likewise. + * tests/test-reallocarray.c (main): Likewise. + * tests/test-fprintf-posix2.c: Likewise. + * tests/test-printf-posix2.c: Likewise. + sigsegv: Port to Fil-C. * lib/sigsegv.in.h (HAVE_STACK_OVERFLOW_RECOVERY): Don't define with Fil-C. diff --git a/tests/test-alignalloc.c b/tests/test-alignalloc.c index c25a0c4734..3ab5b434b8 100644 --- a/tests/test-alignalloc.c +++ b/tests/test-alignalloc.c @@ -48,7 +48,12 @@ main () Stop at 16 MiB alignments because circa-2022 AddressSanitizer goes catatonic with large alignments in posix_memalign, and there seems to be little point to testing them. */ - for (idx_t alignment = 1; alignment <= 16 * 1024 * 1024; alignment *= 2) +#if defined __FILC__ +# define MAX_ALIGNMENT (256 * 1024) +#else +# define MAX_ALIGNMENT (16 * 1024 * 1024) +#endif + for (idx_t alignment = 1; alignment <= MAX_ALIGNMENT; alignment *= 2) for (idx_t size = 1; size <= 1024; size *= 2) { test_alignalloc (alignment, size - 1); diff --git a/tests/test-calloc-gnu.c b/tests/test-calloc-gnu.c index b8fb00c86f..c0b05de572 100644 --- a/tests/test-calloc-gnu.c +++ b/tests/test-calloc-gnu.c @@ -40,12 +40,15 @@ main () free (p); } +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ +#else /* Check that calloc fails when requested to allocate a block of memory larger than PTRDIFF_MAX or SIZE_MAX bytes. */ /* Running this test on a Solaris 10 machine (cfarm210.cfarm.net) makes the machine unresponsive for at least several minutes, possibly indefinitely. */ -#if !defined __sun +# if !defined __sun { for (size_t n = 2; n != 0; n <<= 1) { @@ -58,6 +61,7 @@ main () ASSERT (errno == ENOMEM); } } +# endif #endif return test_exit_status; diff --git a/tests/test-calloc-posix.c b/tests/test-calloc-posix.c index 5c31077501..c163a60e36 100644 --- a/tests/test-calloc-posix.c +++ b/tests/test-calloc-posix.c @@ -34,6 +34,11 @@ void *(*volatile my_calloc) (size_t, size_t) = calloc; int main () { +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ + fputs ("Skipping test: large allocations are unsupported\n", stderr); + return 77; +#else /* Check that calloc sets errno when it fails. Do this only in 64-bit processes, because there are many bi-arch systems nowadays where a 32-bit process can actually allocate 2 GiB of RAM. */ @@ -58,4 +63,5 @@ main () fputs ("Skipping test: size_t is not 64-bits wide\n", stderr); return 77; } +#endif } diff --git a/tests/test-fprintf-posix2.c b/tests/test-fprintf-posix2.c index 2f7f3d2bb0..775af723f6 100644 --- a/tests/test-fprintf-posix2.c +++ b/tests/test-fprintf-posix2.c @@ -22,8 +22,9 @@ /* This test assumes getrlimit() and setrlimit(). With "gcc -fcheck-pointer-bounds -mmpx -static", it produces an - endless loop of "Saw a #BR!" messages. */ -#if HAVE_GETRLIMIT && HAVE_SETRLIMIT && !defined __CHKP__ + endless loop of "Saw a #BR!" messages. + With Fil-C, it produces an error "filc safety error: out of memory". */ +#if HAVE_GETRLIMIT && HAVE_SETRLIMIT && !defined __CHKP__ && !defined __FILC__ #include <stdlib.h> #include <sys/types.h> diff --git a/tests/test-malloc-gnu.c b/tests/test-malloc-gnu.c index 38fe387cc4..d24bf60886 100644 --- a/tests/test-malloc-gnu.c +++ b/tests/test-malloc-gnu.c @@ -38,6 +38,9 @@ main (int argc, _GL_UNUSED char **argv) ASSERT (p != NULL); free (p); +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ +#else /* Check that malloc (n) fails when n exceeds PTRDIFF_MAX. */ /* Note: Running this test on a Solaris 10 machine (cfarm210.cfarm.net) makes the machine unresponsive for 43 seconds. */ @@ -48,6 +51,7 @@ main (int argc, _GL_UNUSED char **argv) ASSERT (p == NULL); ASSERT (errno == ENOMEM); } +#endif return test_exit_status; } diff --git a/tests/test-malloc-posix.c b/tests/test-malloc-posix.c index e64dffb7f9..c923577c69 100644 --- a/tests/test-malloc-posix.c +++ b/tests/test-malloc-posix.c @@ -34,6 +34,11 @@ void *(*volatile my_malloc) (size_t) = malloc; int main () { +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ + fputs ("Skipping test: large allocations are unsupported\n", stderr); + return 77; +#else /* Check that malloc sets errno when it fails. Do this only in 64-bit processes, because there are many bi-arch systems nowadays where a 32-bit process can actually allocate 2 GiB of RAM. */ @@ -58,4 +63,5 @@ main () fputs ("Skipping test: size_t is not 64-bits wide\n", stderr); return 77; } +#endif } diff --git a/tests/test-printf-posix2.c b/tests/test-printf-posix2.c index 4477659766..d551b39ebc 100644 --- a/tests/test-printf-posix2.c +++ b/tests/test-printf-posix2.c @@ -22,8 +22,9 @@ /* This test assumes getrlimit() and setrlimit(). With "gcc -fcheck-pointer-bounds -mmpx -static", it produces an - endless loop of "Saw a #BR!" messages. */ -#if HAVE_GETRLIMIT && HAVE_SETRLIMIT && !defined __CHKP__ + endless loop of "Saw a #BR!" messages. + With Fil-C, it produces an error "filc safety error: out of memory". */ +#if HAVE_GETRLIMIT && HAVE_SETRLIMIT && !defined __CHKP__ && !defined __FILC__ #include <stdlib.h> #include <sys/types.h> diff --git a/tests/test-realloc-posix.c b/tests/test-realloc-posix.c index 0782b2b6ce..70e05c45d9 100644 --- a/tests/test-realloc-posix.c +++ b/tests/test-realloc-posix.c @@ -53,6 +53,9 @@ main (int argc, _GL_UNUSED char **argv) ASSERT (p != NULL); #endif +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ +#else /* Check that realloc (p, n) fails when p is non-null and n exceeds PTRDIFF_MAX. */ if (PTRDIFF_MAX < SIZE_MAX) @@ -83,6 +86,7 @@ main (int argc, _GL_UNUSED char **argv) ASSERT (r == NULL); ASSERT (errno == ENOMEM); } +#endif free (p); return test_exit_status; diff --git a/tests/test-reallocarray.c b/tests/test-reallocarray.c index ec7fbceb4e..66de88bc7a 100644 --- a/tests/test-reallocarray.c +++ b/tests/test-reallocarray.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <errno.h> +#include <stdio.h> #include <stdint.h> #include "signature.h" @@ -36,6 +37,11 @@ void *(*volatile my_reallocarray) (void *, size_t, size_t) = reallocarray; int main () { +#if defined __FILC__ + /* Avoid a "filc safety error: attempt to allocate object that is too big" */ + fputs ("Skipping test: large allocations are unsupported\n", stderr); + return 77; +#else /* Check that reallocarray fails when requested to allocate a block of memory larger than PTRDIFF_MAX or SIZE_MAX bytes. */ for (size_t n = 2; n != 0; n <<= 1) @@ -61,4 +67,5 @@ main () } return test_exit_status; +#endif } -- 2.53.0
