From 6cdb407aa23d8b129e9b9a49a4528c3e0def69e6 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 19 Apr 2024 14:15:30 -0400 Subject: config: Check for strerror_[lr]() --- config/header.mk | 6 +++++- config/strerror-l.c | 11 +++++++++++ config/strerror-r-gnu.c | 11 +++++++++++ config/strerror-r-posix.c | 11 +++++++++++ config/uselocale.c | 9 +++++++++ src/bfstd.c | 42 ++++++++++++++++++++---------------------- 6 files changed, 67 insertions(+), 23 deletions(-) create mode 100644 config/strerror-l.c create mode 100644 config/strerror-r-gnu.c create mode 100644 config/strerror-r-posix.c create mode 100644 config/uselocale.c diff --git a/config/header.mk b/config/header.mk index 55657f8..36ad98e 100644 --- a/config/header.mk +++ b/config/header.mk @@ -20,7 +20,11 @@ HEADERS := \ ${GEN}/posix-spawn-addfchdir.h \ ${GEN}/posix-spawn-addfchdir-np.h \ ${GEN}/statx.h \ - ${GEN}/statx-syscall.h + ${GEN}/statx-syscall.h \ + ${GEN}/strerror-l.h \ + ${GEN}/strerror-r-gnu.h \ + ${GEN}/strerror-r-posix.h \ + ${GEN}/uselocale.h ${GEN}/config.h: ${HEADERS} ${MSG} "[ GEN] ${TGT}" diff --git a/config/strerror-l.c b/config/strerror-l.c new file mode 100644 index 0000000..3dcc4d7 --- /dev/null +++ b/config/strerror-l.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include +#include + +int main(void) { + locale_t locale = duplocale(LC_GLOBAL_LOCALE); + return !strerror_l(ENOMEM, locale); +} diff --git a/config/strerror-r-gnu.c b/config/strerror-r-gnu.c new file mode 100644 index 0000000..26ca0ee --- /dev/null +++ b/config/strerror-r-gnu.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns a pointer + return *strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/config/strerror-r-posix.c b/config/strerror-r-posix.c new file mode 100644 index 0000000..41b2d30 --- /dev/null +++ b/config/strerror-r-posix.c @@ -0,0 +1,11 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include +#include + +int main(void) { + char buf[256]; + // Check that strerror_r() returns an integer + return 2 * strerror_r(ENOMEM, buf, sizeof(buf)); +} diff --git a/config/uselocale.c b/config/uselocale.c new file mode 100644 index 0000000..a712ff8 --- /dev/null +++ b/config/uselocale.c @@ -0,0 +1,9 @@ +// Copyright © Tavian Barnes +// SPDX-License-Identifier: 0BSD + +#include + +int main(void) { + locale_t locale = uselocale((locale_t)0); + return locale == LC_GLOBAL_LOCALE; +} diff --git a/src/bfstd.c b/src/bfstd.c index e2c2b97..1144380 100644 --- a/src/bfstd.c +++ b/src/bfstd.c @@ -317,35 +317,33 @@ const char *xstrerror(int errnum) { const char *ret = NULL; static thread_local char buf[256]; - // - __APPLE__ - // - __COSMOPOLITAN__ - // - No strerror_l() - // - __FreeBSD__ && SANITIZE_MEMORY - // - duplocale() triggers https://github.com/llvm/llvm-project/issues/65532 -#if __APPLE__ || __COSMOPOLITAN__ || (__FreeBSD__ && SANITIZE_MEMORY) - if (strerror_r(errnum, buf, sizeof(buf)) == 0) { - ret = buf; - } -#else -# if __NetBSD__ - // NetBSD has no thread-specific locales - locale_t loc = LC_GLOBAL_LOCALE; -# else + // On FreeBSD with MemorySanitizer, duplocale() triggers + // https://github.com/llvm/llvm-project/issues/65532 +#if BFS_HAS_STRERROR_L && !(__FreeBSD__ && SANITIZE_MEMORY) +# if BFS_HAS_USELOCALE locale_t loc = uselocale((locale_t)0); +# else + locale_t loc = LC_GLOBAL_LOCALE; # endif - locale_t copy = loc; - if (copy == LC_GLOBAL_LOCALE) { - copy = duplocale(copy); + bool free_loc = false; + if (loc == LC_GLOBAL_LOCALE) { + loc = duplocale(loc); + free_loc = true; } - if (copy != (locale_t)0) { - ret = strerror_l(errnum, copy); - - if (loc == LC_GLOBAL_LOCALE) { - freelocale(copy); + if (loc != (locale_t)0) { + ret = strerror_l(errnum, loc); + if (free_loc) { + freelocale(loc); } } +#elif BFS_HAS_STRERROR_R_POSIX + if (strerror_r(errnum, buf, sizeof(buf)) == 0) { + ret = buf; + } +#elif BFS_HAS_STRERROR_R_GNU + ret = strerror_r(errnum, buf, sizeof(buf)); #endif if (!ret) { -- cgit v1.2.3