From 133219ad5cce960ee00eebb0ff8f015e404c2d44 Mon Sep 17 00:00:00 2001 From: Frank Tang Date: Mon, 16 Sep 2019 13:16:21 -0700 Subject: [PATCH] [Intl] Throws exception on grandfather and private locale Bug: v8:9613 Change-Id: Ie91a5bd39c82b6baf33fd84dee8420d2c4a5f504 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1803783 Commit-Queue: Frank Tang Reviewed-by: Jakob Kummerow Cr-Commit-Position: refs/heads/master@{#63815} --- src/objects/intl-objects.cc | 10 ++++++++++ src/objects/intl-objects.h | 2 ++ src/objects/js-locale.cc | 6 ++++-- src/objects/js-locale.h | 3 +++ test/intl/general/case-mapping.js | 3 --- .../grandfathered_tags_without_preferred_value.js | 10 ---------- .../general/language_tags_with_preferred_values.js | 2 -- test/intl/general/supported-locales-of.js | 7 +++---- test/intl/list-format/resolved-options.js | 4 ---- test/intl/regress-8725514.js | 2 +- test/intl/relative-time-format/resolved-options.js | 4 ---- test/test262/test262.status | 5 ----- 12 files changed, 23 insertions(+), 35 deletions(-) diff --git a/src/objects/intl-objects.cc b/src/objects/intl-objects.cc index 13539a72a4..fbbddd3c65 100644 --- a/src/objects/intl-objects.cc +++ b/src/objects/intl-objects.cc @@ -20,6 +20,7 @@ #include "src/objects/js-collator-inl.h" #include "src/objects/js-date-time-format-inl.h" #include "src/objects/js-locale-inl.h" +#include "src/objects/js-locale.h" #include "src/objects/js-number-format-inl.h" #include "src/objects/objects-inl.h" #include "src/objects/property-descriptor.h" @@ -784,6 +785,11 @@ Maybe Intl::CanonicalizeLanguageTag(Isolate* isolate, } std::string locale(locale_str->ToCString().get()); + if (!IsStructurallyValidLanguageTag(locale)) { + THROW_NEW_ERROR_RETURN_VALUE( + isolate, NewRangeError(MessageTemplate::kLocaleBadParameters), + Nothing()); + } return Intl::CanonicalizeLanguageTag(isolate, locale); } @@ -2096,5 +2102,9 @@ MaybeHandle Intl::FormattedToString( return Intl::ToString(isolate, result); } +bool Intl::IsStructurallyValidLanguageTag(const std::string& tag) { + return JSLocale::StartsWithUnicodeLanguageId(tag); +} + } // namespace internal } // namespace v8 diff --git a/src/objects/intl-objects.h b/src/objects/intl-objects.h index aa7e4a87d6..eb432144d0 100644 --- a/src/objects/intl-objects.h +++ b/src/objects/intl-objects.h @@ -337,6 +337,8 @@ class Intl { static const std::set& GetAvailableLocalesForLocale(); static const std::set& GetAvailableLocalesForDateFormat(); + + static bool IsStructurallyValidLanguageTag(const std::string& tag); }; } // namespace internal diff --git a/src/objects/js-locale.cc b/src/objects/js-locale.cc index 4a66ea9eca..2e74f17d9c 100644 --- a/src/objects/js-locale.cc +++ b/src/objects/js-locale.cc @@ -168,10 +168,11 @@ bool IsUnicodeVariantSubtag(const std::string& value) { bool IsExtensionSingleton(const std::string& value) { return IsAlphanum(value, 1, 1); } +} // namespace // TODO(ftang) Replace the following check w/ icu::LocaleBuilder // once ICU64 land in March 2019. -bool StartsWithUnicodeLanguageId(const std::string& value) { +bool JSLocale::StartsWithUnicodeLanguageId(const std::string& value) { // unicode_language_id = // unicode_language_subtag (sep unicode_script_subtag)? // (sep unicode_region_subtag)? (sep unicode_variant_subtag)* ; @@ -207,6 +208,7 @@ bool StartsWithUnicodeLanguageId(const std::string& value) { return true; } +namespace { Maybe ApplyOptionsToTag(Isolate* isolate, Handle tag, Handle options, icu::LocaleBuilder* builder) { @@ -223,7 +225,7 @@ Maybe ApplyOptionsToTag(Isolate* isolate, Handle tag, CHECK_NOT_NULL(*bcp47_tag); // 2. If IsStructurallyValidLanguageTag(tag) is false, throw a RangeError // exception. - if (!StartsWithUnicodeLanguageId(*bcp47_tag)) { + if (!JSLocale::StartsWithUnicodeLanguageId(*bcp47_tag)) { return Just(false); } UErrorCode status = U_ZERO_ERROR; diff --git a/src/objects/js-locale.h b/src/objects/js-locale.h index e1806e6b7f..d1d2b1bd58 100644 --- a/src/objects/js-locale.h +++ b/src/objects/js-locale.h @@ -49,6 +49,9 @@ class JSLocale : public JSObject { static Handle ToString(Isolate* isolate, Handle locale); static std::string ToString(Handle locale); + // Help function to validate locale by other Intl objects. + static bool StartsWithUnicodeLanguageId(const std::string& value); + DECL_CAST(JSLocale) DECL_ACCESSORS(icu_locale, Managed) diff --git a/test/intl/general/case-mapping.js b/test/intl/general/case-mapping.js index 79d1624821..606af09c44 100644 --- a/test/intl/general/case-mapping.js +++ b/test/intl/general/case-mapping.js @@ -125,9 +125,6 @@ assertEquals("abci\u0307", "aBcI\u0307".toLowerCase()); // Anything other than 'tr' and 'az' behave like root for U+0307. assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("fil")); assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("zh-Hant-TW")); -assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("i-klingon")); -assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("i-enochian")); -assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("x-foobar")); // Up to 8 chars are allowed for the primary language tag in BCP 47. assertEquals("abci\u0307", "aBcI\u0307".toLocaleLowerCase("longlang")); diff --git a/test/intl/general/grandfathered_tags_without_preferred_value.js b/test/intl/general/grandfathered_tags_without_preferred_value.js index 808e50d208..16bf369601 100644 --- a/test/intl/general/grandfathered_tags_without_preferred_value.js +++ b/test/intl/general/grandfathered_tags_without_preferred_value.js @@ -8,18 +8,8 @@ // v8 works around that ICU issue. // See https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry . ["cel-gaulish", "cel-gaulish"], - ["i-default", "i-default"], - ["i-mingo", "i-mingo"], - ["i-enochian", "i-enochian"], - ["zh-min", "zh-min"], // Matching should be case-insensitive. - ["I-default", "i-default"], - ["i-DEFAULT", "i-default"], - ["I-DEFAULT", "i-default"], - ["i-DEfauLT", "i-default"], - ["zh-Min", "zh-min"], - ["Zh-min", "zh-min"], ].forEach(([inputLocale, expectedLocale]) => { const canonicalLocales = Intl.getCanonicalLocales(inputLocale); assertEquals(canonicalLocales.length, 1); diff --git a/test/intl/general/language_tags_with_preferred_values.js b/test/intl/general/language_tags_with_preferred_values.js index 4f2fbbfb2e..462bcfb8f7 100644 --- a/test/intl/general/language_tags_with_preferred_values.js +++ b/test/intl/general/language_tags_with_preferred_values.js @@ -9,8 +9,6 @@ // Matching should be case-insensitive. ["sgn-De", "gsg"], - ["sgn-BE-FR", "sfb"], - ["Sgn-bE-Fr", "sfb"], // deprecated region tag ["und-Latn-dd", "und-Latn-DE"], diff --git a/test/intl/general/supported-locales-of.js b/test/intl/general/supported-locales-of.js index eb5c426f07..84984c1d25 100644 --- a/test/intl/general/supported-locales-of.js +++ b/test/intl/general/supported-locales-of.js @@ -83,16 +83,15 @@ for (const service of services) { privateuseLocale = service.supportedLocalesOf("en-US-x-twain"); assertEquals("en-US-x-twain", privateuseLocale[0]); - privateuseLocale2 = service.supportedLocalesOf("x-twain"); - assertEquals(undefined, privateuseLocale2[0]); + assertThrows(() => service.supportedLocalesOf("x-twain"), RangeError); + if (service != Intl.PluralRules) { grandfatheredLocale = service.supportedLocalesOf("art-lojban"); assertEquals(undefined, grandfatheredLocale[0]); } - grandfatheredLocale2 = service.supportedLocalesOf("i-pwn"); - assertEquals(undefined, grandfatheredLocale2[0]); + assertThrows(() => service.supportedLocalesOf("x-pwn"), RangeError); unicodeInPrivateuseLocale = service.supportedLocalesOf( "en-US-x-u-co-phonebk" diff --git a/test/intl/list-format/resolved-options.js b/test/intl/list-format/resolved-options.js index 42687990f9..a2cfff8606 100644 --- a/test/intl/list-format/resolved-options.js +++ b/test/intl/list-format/resolved-options.js @@ -144,7 +144,3 @@ assertEquals( assertEquals( 'ar', (new Intl.ListFormat(['xyz', 'ar'])).resolvedOptions().locale); - -assertEquals( - 'ar', - (new Intl.ListFormat(['i-default', 'ar'])).resolvedOptions().locale); diff --git a/test/intl/regress-8725514.js b/test/intl/regress-8725514.js index 82f884a093..f1bf92b7cc 100644 --- a/test/intl/regress-8725514.js +++ b/test/intl/regress-8725514.js @@ -6,5 +6,5 @@ Object.prototype.__defineGetter__('x', function () { return -2147483648; }); -var f = ["x-u-foo"]; +var f = ["en-US"]; Intl.NumberFormat(f); diff --git a/test/intl/relative-time-format/resolved-options.js b/test/intl/relative-time-format/resolved-options.js index 1caa4f86c9..53648320c9 100644 --- a/test/intl/relative-time-format/resolved-options.js +++ b/test/intl/relative-time-format/resolved-options.js @@ -156,7 +156,3 @@ assertEquals( assertThrows(() => Intl.RelativeTimeFormat.prototype.resolvedOptions.call(receiver), TypeError); } - -assertEquals( - 'ar', - (new Intl.RelativeTimeFormat(['i-default', 'ar'])).resolvedOptions().locale); diff --git a/test/test262/test262.status b/test/test262/test262.status index 1c96ee1dda..7f88a2d711 100644 --- a/test/test262/test262.status +++ b/test/test262/test262.status @@ -530,20 +530,15 @@ # https://bugs.chromium.org/p/v8/issues/detail?id=9613 'intl402/Intl/getCanonicalLocales/canonicalized-tags': [FAIL], 'intl402/Intl/getCanonicalLocales/grandfathered': [FAIL], - 'intl402/Intl/getCanonicalLocales/invalid-tags': [FAIL], 'intl402/Intl/getCanonicalLocales/non-iana-canon': [FAIL], 'intl402/Intl/getCanonicalLocales/preferred-grandfathered': [FAIL], 'intl402/Intl/getCanonicalLocales/preferred-variant': [FAIL], - 'intl402/language-tags-invalid': [FAIL], - 'intl402/ListFormat/constructor/constructor/locales-valid': [FAIL], 'intl402/Locale/constructor-non-iana-canon': [FAIL], 'intl402/Locale/constructor-options-region-valid': [FAIL], 'intl402/Locale/constructor-tag': [FAIL], 'intl402/Locale/getters': [FAIL], 'intl402/Locale/likely-subtags-grandfathered': [FAIL], 'intl402/PluralRules/prototype/resolvedOptions/order': [FAIL], - 'intl402/RelativeTimeFormat/constructor/constructor/locales-valid': [FAIL], - 'intl402/Segmenter/constructor/constructor/locales-valid': [FAIL], ######################## NEEDS INVESTIGATION ###########################