From ee00d25c4efdb521ab91abdc0d2ecf566d789f91 Mon Sep 17 00:00:00 2001 From: Karl Williamson Date: Thu, 18 Feb 2021 13:08:19 -0700 Subject: [PATCH] locale.c: Fix windows bug with broken localeconv() localeconv() was broken on Windows until VS 2015. As a workaround, this was using my_snprintf() to find what the decimal point character is, trying to avoid our workaround for localeconv(), which has a (slight) chance of a race condition. The problem is that my_snprintf() might not end up calling snprintf at all; I didn't trace all possibilities in Windows. So it doesn't make for a reliable sentinel. This commit now specifically uses libc snprintf(), and if it fails, drops down to try localeconv(). --- locale.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/locale.c b/locale.c index 63cb4830031d..c4b21aa2b273 100644 --- a/locale.c +++ b/locale.c @@ -3559,7 +3559,9 @@ Perl_langinfo(const nl_item item) case RADIXCHAR: #if defined(USE_LOCALE_NUMERIC) \ - && (defined(HAS_SOME_LANGINFO) || defined(HAS_SOME_LOCALECONV)) + && ( defined(HAS_SOME_LANGINFO) \ + || defined(HAS_SOME_LOCALECONV) \ + || defined(HAS_SNPRINTF)) cat_index = LC_NUMERIC_INDEX_; break; @@ -3830,10 +3832,15 @@ S_my_langinfo_i(pTHX_ case RADIXCHAR: -# if defined(TS_W32_BROKEN_LOCALECONV) || ! defined(HAS_SOME_LOCALECONV) +# if defined(HAS_SNPRINTF) \ + && (defined(TS_W32_BROKEN_LOCALECONV) || ! defined(HAS_SOME_LOCALECONV)) - /* For this, we output a known simple floating point number to - * a buffer, and parse it, looking for the radix */ + /* snprintf() can be used to find the radix character by outputting a + * known simple floating point number to a buffer, and parsing it, + * inferring the radix as the bytes separating the integer and + * fractional parts. But localeconv() is more direct, not requiring + * inference, so use it if (likely) it is available and doesn't have + * issues. */ { char * floatbuf = NULL; const Size_t initial_size = 10; @@ -3842,13 +3849,13 @@ S_my_langinfo_i(pTHX_ char * item_start; Newx(floatbuf, initial_size, char); - needed_size = my_snprintf(floatbuf, initial_size, "%.1f", 1.5); + needed_size = snprintf(floatbuf, initial_size, "%.1f", 1.5); if (needed_size >= initial_size) { Size_t new_needed; needed_size++; /* insurance */ Renew(floatbuf, needed_size, char); - new_needed = my_snprintf(floatbuf, needed_size, "%.1f", 1.5); + new_needed = snprintf(floatbuf, needed_size, "%.1f", 1.5); assert(new_needed <= needed_size); needed_size = new_needed; } @@ -3891,7 +3898,9 @@ S_my_langinfo_i(pTHX_ # endif # ifdef HAS_SOME_LOCALECONV - /* These items are available from localeconv(). */ + /* These items are available from localeconv(). (To avoid using + * TS_W32_BROKEN_LOCALECONV, one could use GetNumberFormat and + * GetCurrencyFormat; patches welcome) */ case CRNCYSTR: case THOUSEP: