From a2287a13f4e99299ebd9c06f9f98e1bdc7f5089e Mon Sep 17 00:00:00 2001 From: Karl Williamson Date: Mon, 16 Dec 2013 22:34:19 -0700 Subject: [PATCH] Use new macros to make sure LC_NUMERIC is correctly set This uses the macros added in the previous commit to make sure the current LC_NUMERIC locale is correct during the operation being done; restoring it to its prior condition afterwards. Outside of 'use locale' the locale should be C; inside it should be the underlying default locale. The macros handle the whole thing. In most of the places here, the code was trying to do what the macros do more elegantly, but there are some additional places where we set the locale correctly around an operation that is affected by it. --- numeric.c | 4 ++++ pp_ctl.c | 4 ++-- sv.c | 48 ++++++++++-------------------------------------- 3 files changed, 16 insertions(+), 40 deletions(-) diff --git a/numeric.c b/numeric.c index b5144f4..d8e85d9 100644 --- a/numeric.c +++ b/numeric.c @@ -853,6 +853,8 @@ Perl_my_atof(pTHX_ const char* s) PERL_ARGS_ASSERT_MY_ATOF; + { + DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED(); if (PL_numeric_local && PL_numeric_radix_sv && IN_SOME_LOCALE_FORM) { const char *standard = NULL, *local = NULL; bool use_standard_radix; @@ -878,6 +880,8 @@ Perl_my_atof(pTHX_ const char* s) } else Perl_atof2(s, x); + RESTORE_LC_NUMERIC(); + } #else Perl_atof2(s, x); #endif diff --git a/pp_ctl.c b/pp_ctl.c index 7236921..d47e983 100644 --- a/pp_ctl.c +++ b/pp_ctl.c @@ -836,13 +836,13 @@ PP(pp_formline) } /* Formats aren't yet marked for locales, so assume "yes". */ { - STORE_NUMERIC_STANDARD_SET_LOCAL(); + DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED(); arg &= ~(FORM_NUM_POINT|FORM_NUM_BLANK); /* we generate fmt ourselves so it is safe */ GCC_DIAG_IGNORE(-Wformat-nonliteral); my_snprintf(t, SvLEN(PL_formtarget) - (t - SvPVX(PL_formtarget)), fmt, (int) fieldsize, (int) arg, value); GCC_DIAG_RESTORE; - RESTORE_NUMERIC_STANDARD(); + RESTORE_LC_NUMERIC(); } t += fieldsize; break; diff --git a/sv.c b/sv.c index 93d6a1a..676340b 100644 --- a/sv.c +++ b/sv.c @@ -2957,31 +2957,19 @@ Perl_sv_2pv_flags(pTHX_ SV *const sv, STRLEN *const lp, const I32 flags) V_Gconvert(SvNVX(sv), NV_DIG, 0, s); SvPOK_on(sv); #else - /* Gconvert always uses the current locale. That's the right thing - * to do if we're supposed to be using locales. But otherwise, we - * want the result to be based on the C locale, so we need to - * change to the C locale during the Gconvert and then change back. - * But if we're already in the C locale (PL_numeric_standard is - * TRUE in that case), no need to do any changing */ - if (PL_numeric_standard || IN_SOME_LOCALE_FORM_RUNTIME) { + { + DECLARE_STORE_LC_NUMERIC_SET_TO_NEEDED(); V_Gconvert(SvNVX(sv), NV_DIG, 0, s); /* If the radix character is UTF-8, and actually is in the * output, turn on the UTF-8 flag for the scalar */ - if (! PL_numeric_standard + if (PL_numeric_local && PL_numeric_radix_sv && SvUTF8(PL_numeric_radix_sv) && instr(s, SvPVX_const(PL_numeric_radix_sv))) { SvUTF8_on(sv); } - } - else { - char *loc = savepv(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - V_Gconvert(SvNVX(sv), NV_DIG, 0, s); - setlocale(LC_NUMERIC, loc); - Safefree(loc); - + RESTORE_LC_NUMERIC(); } /* We don't call SvPOK_on(), because it may come to pass that the @@ -10423,9 +10411,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p char ebuf[IV_DIG * 4 + NV_DIG + 32]; /* large enough for "%#.#f" --chip */ /* what about long double NVs? --jhi */ -#ifdef USE_LOCALE_NUMERIC - SV* oldlocale = NULL; -#endif + + DECLARATION_FOR_STORE_LC_NUMERIC_SET_TO_NEEDED; PERL_ARGS_ASSERT_SV_VCATPVFN_FLAGS; PERL_UNUSED_ARG(maybe_tainted); @@ -10478,6 +10465,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p a Configure test for this. */ if (digits && digits < sizeof(ebuf) - NV_DIG - 10) { /* 0, point, slack */ + STORE_LC_NUMERIC_SET_TO_NEEDED(); V_Gconvert(nv, (int)digits, 0, ebuf); sv_catpv_nomg(sv, ebuf); if (*ebuf) /* May return an empty string for digits==0 */ @@ -11338,6 +11326,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p /* See earlier comment about buggy Gconvert when digits, aka precis is 0 */ if ( c == 'g' && precis) { + STORE_LC_NUMERIC_SET_TO_NEEDED(); V_Gconvert((NV)nv, (int)precis, 0, PL_efloatbuf); /* May return an empty string for digits==0 */ if (*PL_efloatbuf) { @@ -11387,19 +11376,7 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p * where printf() taints but print($float) doesn't. * --jhi */ -#ifdef USE_LOCALE_NUMERIC - if (! PL_numeric_standard && ! IN_SOME_LOCALE_FORM) { - - /* We use a mortal SV, so that any failures (such as if - * warnings are made fatal) won't leak */ - char *oldlocale_string = setlocale(LC_NUMERIC, NULL); - oldlocale = newSVpvn_flags(oldlocale_string, - strlen(oldlocale_string), - SVs_TEMP); - PL_numeric_standard = TRUE; - setlocale(LC_NUMERIC, "C"); - } -#endif + STORE_LC_NUMERIC_SET_TO_NEEDED(); /* hopefully the above makes ptr a very constrained format * that is safe to use, even though it's not literal */ @@ -11581,13 +11558,8 @@ Perl_sv_vcatpvfn_flags(pTHX_ SV *const sv, const char *const pat, const STRLEN p } SvTAINT(sv); -#ifdef USE_LOCALE_NUMERIC /* Done outside loop, so don't have to save/restore + RESTORE_LC_NUMERIC(); /* Done outside loop, so don't have to save/restore each iteration. */ - if (oldlocale) { - setlocale(LC_NUMERIC, SvPVX(oldlocale)); - PL_numeric_standard = FALSE; - } -#endif } /* ========================================================================= -- 2.7.4