From 017e67ddde79fa2b6187a5e56b1e92bafc7c4cd2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Fri, 14 Sep 2018 13:00:41 -0400 Subject: [PATCH] drop lazy plural forms init in dcngettext there is no good reason to wait to find and process the plural rules for a translated message file until a gettext form requesting plural rule processing is used. it just imposes additional synchronization, here in the form of clunky use of atomics. it looks like there may also have been a race condition where nplurals could be seen without plural_rule being seen, possibly leading to null pointer dereference. if so, this commit fixes it. --- src/locale/dcngettext.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/locale/dcngettext.c b/src/locale/dcngettext.c index 7fbe7196..8b891d00 100644 --- a/src/locale/dcngettext.c +++ b/src/locale/dcngettext.c @@ -100,8 +100,8 @@ struct msgcat { struct msgcat *next; const void *map; size_t map_size; - void *volatile plural_rule; - volatile int nplurals; + const char *plural_rule; + int nplurals; struct binding *binding; const struct __locale_map *lm; int cat; @@ -200,20 +200,7 @@ notrans: p->lm = lm; p->map = map; p->map_size = map_size; - do { - old_cats = cats; - p->next = old_cats; - } while (a_cas_p(&cats, old_cats, p) != old_cats); - } - - const char *trans = __mo_lookup(p->map, p->map_size, msgid1); - if (!trans) goto notrans; - - /* Non-plural-processing gettext forms pass a null pointer as - * msgid2 to request that dcngettext suppress plural processing. */ - if (!msgid2) return (char *)trans; - if (!p->plural_rule) { const char *rule = "n!=1;"; unsigned long np = 2; const char *r = __mo_lookup(p->map, p->map_size, ""); @@ -237,10 +224,22 @@ notrans: rule = r+7; } } - a_store(&p->nplurals, np); - a_cas_p(&p->plural_rule, 0, (void *)rule); + p->nplurals = np; + p->plural_rule = rule; + + do { + old_cats = cats; + p->next = old_cats; + } while (a_cas_p(&cats, old_cats, p) != old_cats); } - if (p->nplurals) { + + const char *trans = __mo_lookup(p->map, p->map_size, msgid1); + if (!trans) goto notrans; + + /* Non-plural-processing gettext forms pass a null pointer as + * msgid2 to request that dcngettext suppress plural processing. */ + + if (msgid2 && p->nplurals) { unsigned long plural = __pleval(p->plural_rule, n); if (plural > p->nplurals) goto notrans; while (plural--) { -- 2.25.1