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.
This commit is contained in:
Mahmoud Al-Qudsi 2019-01-02 17:25:33 -06:00
parent 72423c517a
commit a1df72dbb6
2 changed files with 15 additions and 4 deletions

View file

@ -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.

View file

@ -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