Skip to content

Commit

Permalink
Fix wcstod_l infinite recursion under FreeBSD
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mqudsi committed Jan 3, 2019
1 parent 7af0cad commit bc0a0b4
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 4 deletions.
7 changes: 4 additions & 3 deletions src/fallback.cpp
Expand Up @@ -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.
Expand Down
12 changes: 11 additions & 1 deletion src/fallback.h
Expand Up @@ -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

0 comments on commit bc0a0b4

Please sign in to comment.