Skip to content

Commit bd3b397

Browse files
author
John Peacock
committed
Apply upstream core changes from [email protected]
1 parent 39bb182 commit bd3b397

File tree

2 files changed

+115
-41
lines changed

2 files changed

+115
-41
lines changed

vutil/vutil.c

Lines changed: 100 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -618,42 +618,80 @@ Perl_upg_version(pTHX_ SV *ver, bool qv)
618618
goto VER_PV;
619619
}
620620
#endif
621-
622621
#ifdef USE_LOCALE_NUMERIC
622+
623623
{
624-
const char * const cur_numeric = setlocale(LC_NUMERIC, NULL);
625-
assert(cur_numeric);
626-
627-
/* XS code can set the locale without us knowing. To protect the
628-
* version number parsing, which requires the radix character to be a
629-
* dot, update our records as to what the locale is, so that our
630-
* existing macro mechanism can correctly change it to a dot and back
631-
* if necessary. This code is extremely unlikely to be in a loop, so
632-
* the extra work will have a negligible performance impact. See [perl
633-
* #121930].
634-
*
635-
* If the current locale is a standard one, but we are expecting it to
636-
* be a different, underlying locale, update our records to make the
637-
* underlying locale this (standard) one. If the current locale is not
638-
* a standard one, we should be expecting a non-standard one, the same
639-
* one that we have recorded as the underlying locale. If not, update
640-
* our records. */
641-
if (strEQ(cur_numeric, "C") || strEQ(cur_numeric, "POSIX")) {
642-
if (! PL_numeric_standard) {
643-
new_numeric(cur_numeric);
644-
}
645-
}
646-
else if (PL_numeric_standard
647-
|| ! PL_numeric_name
648-
|| strNE(PL_numeric_name, cur_numeric))
649-
{
650-
new_numeric(cur_numeric);
624+
/* This may or may not be called from code that has switched
625+
* locales without letting perl know, therefore we have to find it
626+
* from first principals. See [perl #121930]. */
627+
628+
/* In windows, or not threaded, or not thread-safe, if it isn't C,
629+
* set it to C. */
630+
631+
# ifndef USE_POSIX_2008_LOCALE
632+
633+
const char * locale_name_on_entry;
634+
635+
LC_NUMERIC_LOCK(0); /* Start critical section */
636+
637+
locale_name_on_entry = setlocale(LC_NUMERIC, NULL);
638+
if ( strNE(locale_name_on_entry, "C")
639+
&& strNE(locale_name_on_entry, "POSIX"))
640+
{
641+
setlocale(LC_NUMERIC, "C");
642+
}
643+
else { /* This value indicates to the restore code that we didn't
644+
change the locale */
645+
locale_name_on_entry = NULL;
646+
}
647+
648+
# else
649+
650+
const locale_t locale_obj_on_entry = uselocale((locale_t) 0);
651+
const char * locale_name_on_entry = NULL;
652+
DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
653+
654+
if (locale_obj_on_entry == LC_GLOBAL_LOCALE) {
655+
656+
/* in the global locale, we can call system setlocale and if it
657+
* isn't C, set it to C. */
658+
LC_NUMERIC_LOCK(0);
659+
660+
locale_name_on_entry = setlocale(LC_NUMERIC, NULL);
661+
if ( strNE(locale_name_on_entry, "C")
662+
&& strNE(locale_name_on_entry, "POSIX"))
663+
{
664+
setlocale(LC_NUMERIC, "C");
665+
}
666+
else { /* This value indicates to the restore code that we
667+
didn't change the locale */
668+
locale_name_on_entry = NULL;
651669
}
652670
}
671+
else if (locale_obj_on_entry == PL_underlying_numeric_obj) {
672+
/* Here, the locale appears to have been changed to use the
673+
* program's underlying locale. Just use our mechanisms to
674+
* switch back to C. It might be possible for this pointer to
675+
* actually refer to something else if it got released and
676+
* reused somehow. But it doesn't matter, our mechanisms will
677+
* work even so */
678+
STORE_LC_NUMERIC_SET_STANDARD();
679+
}
680+
else if (locale_obj_on_entry != PL_C_locale_obj) {
681+
/* The C object should be unchanged during a program's
682+
* execution, so it should be safe to assume it means what it
683+
* says, so if we are in it, no locale change is required.
684+
* Otherwise, simply use the thread-safe operation. */
685+
uselocale(PL_C_locale_obj);
686+
}
687+
688+
# endif
689+
690+
/* Prevent recursed calls from trying to change back */
691+
LOCK_LC_NUMERIC_STANDARD();
692+
653693
#endif
654-
{ /* Braces needed because macro just below declares a variable */
655-
STORE_NUMERIC_LOCAL_SET_STANDARD();
656-
LOCK_NUMERIC_STANDARD();
694+
657695
if (sv) {
658696
Perl_sv_catpvf(aTHX_ sv, "%.9"NVff, SvNVX(ver));
659697
len = SvCUR(sv);
@@ -663,9 +701,38 @@ Perl_upg_version(pTHX_ SV *ver, bool qv)
663701
len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver));
664702
buf = tbuf;
665703
}
666-
UNLOCK_NUMERIC_STANDARD();
667-
RESTORE_NUMERIC_LOCAL();
704+
705+
#ifdef USE_LOCALE_NUMERIC
706+
707+
UNLOCK_LC_NUMERIC_STANDARD();
708+
709+
# ifndef USE_POSIX_2008_LOCALE
710+
711+
if (locale_name_on_entry) {
712+
setlocale(LC_NUMERIC, locale_name_on_entry);
713+
}
714+
715+
LC_NUMERIC_UNLOCK; /* End critical section */
716+
717+
# else
718+
719+
if (locale_name_on_entry) {
720+
setlocale(LC_NUMERIC, locale_name_on_entry);
721+
LC_NUMERIC_UNLOCK;
722+
}
723+
else if (locale_obj_on_entry == PL_underlying_numeric_obj) {
724+
RESTORE_LC_NUMERIC();
725+
}
726+
else if (locale_obj_on_entry != PL_C_locale_obj) {
727+
uselocale(locale_obj_on_entry);
728+
}
729+
730+
# endif
731+
668732
}
733+
734+
#endif /* USE_LOCALE_NUMERIC */
735+
669736
while (buf[len-1] == '0' && len > 0) len--;
670737
if ( buf[len-1] == '.' ) len--; /* eat the trailing decimal */
671738
version = savepvn(buf, len);

vutil/vutil.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ S_croak_xs_usage(pTHX_ const CV *const cv, const char *const params)
115115
Perl_croak_nocontext("Usage: %s(%s)", gvname, params);
116116
} else {
117117
/* Pants. I don't think that it should be possible to get here. */
118-
Perl_croak_nocontext("Usage: CODE(0x%" UVxf ")(%s)", PTR2UV(cv), params);
118+
Perl_croak_nocontext("Usage: CODE(0x%"UVxf")(%s)", PTR2UV(cv), params);
119119
}
120120
}
121121

@@ -223,20 +223,27 @@ const char * Perl_prescan_version(pTHX_ const char *s, bool strict, const char**
223223
#endif
224224

225225

226+
#if PERL_VERSION_LT(5,27,9)
227+
# define LC_NUMERIC_LOCK
228+
# define LC_NUMERIC_UNLOCK
226229
#if PERL_VERSION_LT(5,19,0)
227-
# undef STORE_NUMERIC_LOCAL_SET_STANDARD
228-
# undef RESTORE_NUMERIC_LOCAL
230+
# undef STORE_LC_NUMERIC_SET_STANDARD
231+
# undef RESTORE_LC_NUMERIC
232+
# undef DECLARATION_FOR_LC_NUMERIC_MANIPULATION
229233
# ifdef USE_LOCALE
230-
# define STORE_NUMERIC_LOCAL_SET_STANDARD()\
231-
char *loc = savepv(setlocale(LC_NUMERIC, NULL)); \
234+
# define DECLARATION_FOR_LC_NUMERIC_MANIPULATION char *loc
235+
# define STORE_NUMERIC_SET_STANDARD()\
236+
loc = savepv(setlocale(LC_NUMERIC, NULL)); \
232237
SAVEFREEPV(loc); \
233238
setlocale(LC_NUMERIC, "C");
234239

235-
# define RESTORE_NUMERIC_LOCAL()\
240+
# define RESTORE_LC_NUMERIC()\
236241
setlocale(LC_NUMERIC, loc);
237242
# else
238-
# define STORE_NUMERIC_LOCAL_SET_STANDARD()
239-
# define RESTORE_NUMERIC_LOCAL()
243+
# define DECLARATION_FOR_LC_NUMERIC_MANIPULATION
244+
# define STORE_LC_NUMERIC_SET_STANDARD()
245+
# define RESTORE_LC_NUMERIC()
246+
# endif
240247
# endif
241248
#endif
242249

0 commit comments

Comments
 (0)