From owner-dev-commits-src-all@freebsd.org Fri Sep 17 15:00:41 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E44176B494A; Fri, 17 Sep 2021 15:00:41 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4H9xw95wMCz3Bn2; Fri, 17 Sep 2021 15:00:41 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id ACADD169C6; Fri, 17 Sep 2021 15:00:41 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 18HF0f4W030257; Fri, 17 Sep 2021 15:00:41 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 18HF0fGr030256; Fri, 17 Sep 2021 15:00:41 GMT (envelope-from git) Date: Fri, 17 Sep 2021 15:00:41 GMT Message-Id: <202109171500.18HF0fGr030256@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Mark Johnston Subject: git: 7eb138a9e536 - main - libc/locale: Fix races between localeconv(3) and setlocale(3) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: markj X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 7eb138a9e53636366e615bdf04062fedc044bcea Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 17 Sep 2021 15:00:42 -0000 The branch main has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=7eb138a9e53636366e615bdf04062fedc044bcea commit 7eb138a9e53636366e615bdf04062fedc044bcea Author: Mark Johnston AuthorDate: 2021-09-17 14:44:23 +0000 Commit: Mark Johnston CommitDate: 2021-09-17 14:47:46 +0000 libc/locale: Fix races between localeconv(3) and setlocale(3) Each locale embeds a lazily initialized lconv which is populated by localeconv(3) and localeconv_l(3). When setlocale(3) updates the global locale, the lconv needs to be (lazily) reinitialized. To signal this, we set flag variables in the locale structure. There are two problems: - The flags are set before the locale is fully updated, so a concurrent localeconv() call can observe partially initialized locale data. - No barriers ensure that localeconv() observes a fully initialized locale if a flag is set. So, move the flag update appropriately, and use acq/rel barriers to provide some synchronization. Note that this is inadequate in the face of multiple concurrent calls to setlocale(3), but this is not expected to work regardless. Thanks to Henry Hu for providing a test case demonstrating the race. PR: 258360 MFC after: 3 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D31899 --- lib/libc/locale/lmonetary.c | 4 ++-- lib/libc/locale/lnumeric.c | 4 ++-- lib/libc/locale/localeconv.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c index 99800ae69922..b8b4e78c060b 100644 --- a/lib/libc/locale/lmonetary.c +++ b/lib/libc/locale/lmonetary.c @@ -107,8 +107,6 @@ monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale, &loc->buffer, "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN, (const char **)l); - if (ret != _LDP_ERROR) - *changed = 1; if (ret == _LDP_LOADED) { l->mon_grouping = __fix_locale_grouping_str(l->mon_grouping); @@ -146,6 +144,8 @@ monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale, M_ASSIGN_ICHAR(p_sign_posn); M_ASSIGN_ICHAR(n_sign_posn); } + if (ret != _LDP_ERROR) + atomic_store_rel_int(changed, 1); return (ret); } int diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c index 046d1f1817dc..cc1daa3863e3 100644 --- a/lib/libc/locale/lnumeric.c +++ b/lib/libc/locale/lnumeric.c @@ -73,8 +73,6 @@ numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed &loc->buffer, "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE, (const char**)l); - if (ret != _LDP_ERROR) - *changed= 1; if (ret == _LDP_LOADED) { /* Can't be empty according to C99 */ if (*l->decimal_point == '\0') @@ -83,6 +81,8 @@ numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed l->grouping = __fix_locale_grouping_str(l->grouping); } + if (ret != _LDP_ERROR) + atomic_store_rel_int(changed, 1); return (ret); } diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c index 641773944e32..130f93c178f4 100644 --- a/lib/libc/locale/localeconv.c +++ b/lib/libc/locale/localeconv.c @@ -65,7 +65,7 @@ localeconv_l(locale_t loc) FIX_LOCALE(loc); struct lconv *ret = &loc->lconv; - if (loc->monetary_locale_changed) { + if (atomic_load_acq_int(&loc->monetary_locale_changed) != 0) { /* LC_MONETARY part */ struct lc_monetary_T * mptr; @@ -94,10 +94,10 @@ localeconv_l(locale_t loc) M_ASSIGN_CHAR(int_n_sep_by_space); M_ASSIGN_CHAR(int_p_sign_posn); M_ASSIGN_CHAR(int_n_sign_posn); - loc->monetary_locale_changed = 0; + atomic_store_int(&loc->monetary_locale_changed, 0); } - if (loc->numeric_locale_changed) { + if (atomic_load_acq_int(&loc->numeric_locale_changed) != 0) { /* LC_NUMERIC part */ struct lc_numeric_T * nptr; @@ -107,7 +107,7 @@ localeconv_l(locale_t loc) N_ASSIGN_STR(decimal_point); N_ASSIGN_STR(thousands_sep); N_ASSIGN_STR(grouping); - loc->numeric_locale_changed = 0; + atomic_store_int(&loc->numeric_locale_changed, 0); } return ret;