mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-10-09 12:24:08 +00:00
[libcxx] [Windows] Store the lconv struct returned from localeconv in locale_t
This fixes using non-default locales, which currently can crash when e.g. formatting numbers. Within the localeconv_l function, the per-thread locale is temporarily changed with __libcpp_locale_guard, then localeconv() is called, returning an lconv * struct pointer. When localeconv_l returns, the __libcpp_locale_guard dtor restores the per-thread locale back to the original. This invalidates the contents of the earlier returned lconv struct, and all C strings that are pointed to within it are also invalidated. Thus, to have an actually working localeconv_l function, the function needs to allocate some sort of storage for the returned contents, that stays valid for as long as the caller needs to use the returned struct. Extend the libcxx/win32 specific locale_t class with storage for a deep copy of a lconv struct, and change localeconv_l to take a reference to the locale_t, to allow it to store the returned lconv struct there. This works fine for libcxx itself, but wouldn't necessarily be right for a caller that uses libcxx's localeconv_l function. This fixes around 11 of libcxx's currently failing tests on windows. Differential Revision: https://reviews.llvm.org/D69505
This commit is contained in:
parent
d3cea95475
commit
7db4f2c694
@ -28,14 +28,72 @@
|
||||
| LC_NUMERIC_MASK \
|
||||
| LC_TIME_MASK )
|
||||
|
||||
class __lconv_storage {
|
||||
public:
|
||||
__lconv_storage(const lconv *__lc_input) {
|
||||
__lc = *__lc_input;
|
||||
|
||||
__decimal_point = __lc_input->decimal_point;
|
||||
__thousands_sep = __lc_input->thousands_sep;
|
||||
__grouping = __lc_input->grouping;
|
||||
__int_curr_symbol = __lc_input->int_curr_symbol;
|
||||
__currency_symbol = __lc_input->currency_symbol;
|
||||
__mon_decimal_point = __lc_input->mon_decimal_point;
|
||||
__mon_thousands_sep = __lc_input->mon_thousands_sep;
|
||||
__mon_grouping = __lc_input->mon_grouping;
|
||||
__positive_sign = __lc_input->positive_sign;
|
||||
__negative_sign = __lc_input->negative_sign;
|
||||
|
||||
__lc.decimal_point = const_cast<char *>(__decimal_point.c_str());
|
||||
__lc.thousands_sep = const_cast<char *>(__thousands_sep.c_str());
|
||||
__lc.grouping = const_cast<char *>(__grouping.c_str());
|
||||
__lc.int_curr_symbol = const_cast<char *>(__int_curr_symbol.c_str());
|
||||
__lc.currency_symbol = const_cast<char *>(__currency_symbol.c_str());
|
||||
__lc.mon_decimal_point = const_cast<char *>(__mon_decimal_point.c_str());
|
||||
__lc.mon_thousands_sep = const_cast<char *>(__mon_thousands_sep.c_str());
|
||||
__lc.mon_grouping = const_cast<char *>(__mon_grouping.c_str());
|
||||
__lc.positive_sign = const_cast<char *>(__positive_sign.c_str());
|
||||
__lc.negative_sign = const_cast<char *>(__negative_sign.c_str());
|
||||
}
|
||||
|
||||
lconv *__get() {
|
||||
return &__lc;
|
||||
}
|
||||
private:
|
||||
lconv __lc;
|
||||
std::string __decimal_point;
|
||||
std::string __thousands_sep;
|
||||
std::string __grouping;
|
||||
std::string __int_curr_symbol;
|
||||
std::string __currency_symbol;
|
||||
std::string __mon_decimal_point;
|
||||
std::string __mon_thousands_sep;
|
||||
std::string __mon_grouping;
|
||||
std::string __positive_sign;
|
||||
std::string __negative_sign;
|
||||
};
|
||||
|
||||
class locale_t {
|
||||
public:
|
||||
locale_t()
|
||||
: __locale(nullptr), __locale_str(nullptr) {}
|
||||
: __locale(nullptr), __locale_str(nullptr), __lc(nullptr) {}
|
||||
locale_t(std::nullptr_t)
|
||||
: __locale(nullptr), __locale_str(nullptr) {}
|
||||
: __locale(nullptr), __locale_str(nullptr), __lc(nullptr) {}
|
||||
locale_t(_locale_t __xlocale, const char* __xlocale_str)
|
||||
: __locale(__xlocale), __locale_str(__xlocale_str) {}
|
||||
: __locale(__xlocale), __locale_str(__xlocale_str), __lc(nullptr) {}
|
||||
locale_t(const locale_t &__l)
|
||||
: __locale(__l.__locale), __locale_str(__l.__locale_str), __lc(nullptr) {}
|
||||
|
||||
~locale_t() {
|
||||
delete __lc;
|
||||
}
|
||||
|
||||
locale_t &operator =(const locale_t &__l) {
|
||||
__locale = __l.__locale;
|
||||
__locale_str = __l.__locale_str;
|
||||
// __lc not copied
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend bool operator==(const locale_t& __left, const locale_t& __right) {
|
||||
return __left.__locale == __right.__locale;
|
||||
@ -94,9 +152,16 @@ public:
|
||||
operator _locale_t() const {
|
||||
return __locale;
|
||||
}
|
||||
|
||||
lconv *__store_lconv(const lconv *__input_lc) {
|
||||
delete __lc;
|
||||
__lc = new __lconv_storage(__input_lc);
|
||||
return __lc->__get();
|
||||
}
|
||||
private:
|
||||
_locale_t __locale;
|
||||
const char* __locale_str;
|
||||
__lconv_storage *__lc = nullptr;
|
||||
};
|
||||
|
||||
// Locale management functions
|
||||
@ -109,7 +174,7 @@ locale_t newlocale( int mask, const char * locale, locale_t base );
|
||||
// We can still implement raii even without uselocale though.
|
||||
|
||||
|
||||
lconv *localeconv_l( locale_t loc );
|
||||
lconv *localeconv_l( locale_t &loc );
|
||||
size_t mbrlen_l( const char *__restrict s, size_t n,
|
||||
mbstate_t *__restrict ps, locale_t loc);
|
||||
size_t mbsrtowcs_l( wchar_t *__restrict dst, const char **__restrict src,
|
||||
|
@ -32,11 +32,13 @@ decltype(MB_CUR_MAX) MB_CUR_MAX_L( locale_t __l )
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
lconv *localeconv_l( locale_t loc )
|
||||
lconv *localeconv_l( locale_t &loc )
|
||||
{
|
||||
__libcpp_locale_guard __current(loc);
|
||||
return localeconv();
|
||||
lconv *lc = localeconv();
|
||||
if (!lc)
|
||||
return lc;
|
||||
return loc.__store_lconv(lc);
|
||||
}
|
||||
size_t mbrlen_l( const char *__restrict s, size_t n,
|
||||
mbstate_t *__restrict ps, locale_t loc )
|
||||
|
Loading…
Reference in New Issue
Block a user