From a1df72dbb60f26b1ca6e24b6c3fd39e07a6ebf14 Mon Sep 17 00:00:00 2001 From: Mahmoud Al-Qudsi Date: Wed, 2 Jan 2019 17:25:33 -0600 Subject: [PATCH] Fix `wcstod_l` infinite recursion under FreeBSD This was the actual issue leading to memory corruption under FreeBSD in issue #5453, worked around by correcting the detection of `wcstod_l` so that our version of the function is not called at all. If we are 100% certain that `wcstod_l` does not exist, then then the existing code is fine. But given that our checks have failed seperately on two different platforms already (FreeBSD and Cygwin/newlib), it's a good precaution to take. --- src/fallback.cpp | 7 ++++--- src/fallback.h | 12 +++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/fallback.cpp b/src/fallback.cpp index d7e4e508e..8a7d6a0e2 100644 --- a/src/fallback.cpp +++ b/src/fallback.cpp @@ -390,9 +390,10 @@ int flock(int fd, int op) { #endif // HAVE_FLOCK #ifndef HAVE_WCSTOD_L -// musl doesn't feature wcstod_l, -// so we just wrap wcstod. -double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { +#undef wcstod_l +// For platforms without wcstod_l C extension, wrap wcstod after changing the +// thread-specific locale. +double fish_compat::wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc) { char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL)); // Yes, this is hardcoded to use the "C" locale. // That's the only thing we need, and uselocale(loc) broke in my testing. diff --git a/src/fallback.h b/src/fallback.h index f8b7d4977..b935c8460 100644 --- a/src/fallback.h +++ b/src/fallback.h @@ -200,5 +200,15 @@ int flock(int fd, int op); #endif #ifndef HAVE_WCSTOD_L -double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc); +// On some platforms if this is incorrectly detected and a system-defined +// defined version of `wcstod_l` exists, calling `wcstod` from our own +// `wcstod_l` can call back into `wcstod_l` causing infinite recursion. +// e.g. FreeBSD defines `wcstod(x, y)` as `wcstod_l(x, y, __get_locale())`. +// Solution: namespace our implementation to make sure there is no symbol +// duplication. +#undef wcstod_l +namespace fish_compat { + double wcstod_l(const wchar_t *enptr, wchar_t **endptr, locale_t loc); +} +#define wcstod_l(x, y, z) fish_compat::wcstod_l(x, y, z) #endif