-
Notifications
You must be signed in to change notification settings - Fork 15.2k
Description
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
llvm-project/libcxx/include/__locale_dir/support/linux.h
Lines 85 to 95 in 79cd1b7
| 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:
- In LLVM code: libcxx/include/__locale_dir/support/linux.h
- In LLVM code: libcxx/include/__locale_dir/locale_base_api/musl.h
- In musl libc code:
include/stdlib.h(around lines 28-35)
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 therestrictkeyword) - 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
- this is the root cause of why _GNU_SOURCE can not be assumed by just
#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 thelocal_targument and returns the two-argument (e.g., nonlocal aware) form)