Skip to content

configurations for Strtonum functions in libcxx are partial/incomplete when '_LIBCPP_HAS_MUSL_LIBC' is defined. #167977

@reactive-firewall

Description

@reactive-firewall

Affects llvm-project versions: <= 21.1.5 (possibly others)
Affects platforms: linux (with musl's libc)
Affects subprojects: libcxxabi, libcxx

context

When building libcxx with configurations that result in -D_LIBCPP_HAS_MUSL_LIBC & -D__linux__ but LACK _GNU_SOURCE (e.g., system musl libc built with _BSD_SOURCE instead of _GNU_SOURCE) will
cascade to cause issues with 'Strtonum functions' in libcxx/include/__locale_dir/support/linux.h namely:

  • __strtof
  • __strtod
  • __strtold

See relevant code here

inline _LIBCPP_HIDE_FROM_ABI float __strtof(const char* __nptr, char** __endptr, __locale_t __loc) {
return ::strtof_l(__nptr, __endptr, __loc);
}
inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr, __locale_t __loc) {
return ::strtod_l(__nptr, __endptr, __loc);
}
inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __endptr, __locale_t __loc) {
return ::strtold_l(__nptr, __endptr, __loc);
}

errors present as:

error: no member named 'strtof_l' in the global namespace

error: no member named 'strtod_l' in the global namespace

error: no member named 'strtold_l' in the global namespace

suggested fix:

Handle the same guards used by musl libc to conditionally compile the function as already done for __strtoll and __strtoull (also found in libcxx/include/__locale_dir/support/linux.h)

//
// Strtonum functions
//
inline _LIBCPP_HIDE_FROM_ABI float __strtof(const char* __nptr, char** __endptr, __locale_t __loc) {
#if !_LIBCPP_HAS_MUSL_LIBC || defined(_GNU_SOURCE)
  return ::strtof_l(__nptr, __endptr, __loc);
#else
  (void)__loc;
  return ::strtof(__nptr, __endptr);
#endif
}

inline _LIBCPP_HIDE_FROM_ABI double __strtod(const char* __nptr, char** __endptr, __locale_t __loc) {
#if !_LIBCPP_HAS_MUSL_LIBC || defined(_GNU_SOURCE)
  return ::strtod_l(__nptr, __endptr, __loc);
#else
  (void)__loc;
  return ::strtod(__nptr, __endptr);
#endif
}

inline _LIBCPP_HIDE_FROM_ABI long double __strtold(const char* __nptr, char** __endptr, __locale_t __loc) {
#if !_LIBCPP_HAS_MUSL_LIBC || defined(_GNU_SOURCE)
  return ::strtod_l(__nptr, __endptr, __loc);
#else
  (void)__loc;
  return ::strtold(__nptr, __endptr);
#endif
}

Tip

The musl team would likely consider it a bug not to check defined(_GNU_SOURCE)
However, the musl implementation (circa v1.2.5) just discards the __loc argument even if defined(_GNU_SOURCE) but omits strto*_l completely without it. An over-optimization would be to omit the || defined(_GNU_SOURCE) as it currently has no impact, unless musl were to change their implementation.

References / See-Also

Relevant code in musl libc (circa v1.2.5) can be found in the following files:

float strtof (const char *__restrict, char **__restrict);
double strtod (const char *__restrict, char **__restrict);
long double strtold (const char *__restrict, char **__restrict);
  • In musl libc code: implementation is found in src/stdlib/strtod.c (around lines 17-30) (code seems to target c99+ C standard, using the restrict keyword)
  • In musl libc code: include/stdlib.h (around lines 154-164)
    • this is the root cause of why _GNU_SOURCE can not be assumed by just __linux__ && _LIBCPP_HAS_MUSL_LIBC
#ifdef _GNU_SOURCE
...
struct __locale_struct;
float strtof_l(const char *__restrict, char **__restrict, struct __locale_struct *);
double strtod_l(const char *__restrict, char **__restrict, struct __locale_struct *);
long double strtold_l(const char *__restrict, char **__restrict, struct __locale_struct *);
#endif
  • In musl libc code: implementation for wrappers are found in src/locale/strtod_l.c (around lines 5-22) (implementation just ignores the local_t argument and returns the two-argument (e.g., nonlocal aware) form)

Metadata

Metadata

Assignees

No one assigned

    Labels

    libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions