Skip to content

Commit

Permalink
locale.c: Fix windows bug with broken localeconv()
Browse files Browse the repository at this point in the history
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().
  • Loading branch information
khwilliamson committed Apr 29, 2021
1 parent bd510b4 commit 98b56eb
Showing 1 changed file with 16 additions and 7 deletions.
23 changes: 16 additions & 7 deletions locale.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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:
Expand Down

0 comments on commit 98b56eb

Please sign in to comment.