summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/header.mk6
-rw-r--r--config/strerror-l.c11
-rw-r--r--config/strerror-r-gnu.c11
-rw-r--r--config/strerror-r-posix.c11
-rw-r--r--config/uselocale.c9
-rw-r--r--src/bfstd.c42
6 files changed, 67 insertions, 23 deletions
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 <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include <errno.h>
+#include <locale.h>
+#include <string.h>
+
+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 <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include <errno.h>
+#include <string.h>
+
+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 <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include <errno.h>
+#include <string.h>
+
+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 <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include <locale.h>
+
+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) {