summaryrefslogtreecommitdiff
path: root/src/locale
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-09-14 13:00:41 -0400
committerRich Felker <dalias@aerifal.cx>2018-09-14 13:11:19 -0400
commit017e67ddde79fa2b6187a5e56b1e92bafc7c4cd2 (patch)
treeb3fd75dcf61708f262adbb42863524e01caf9f47 /src/locale
parent12817793301398241b6cb00c740f0d3ca41076e9 (diff)
downloadmusl-017e67ddde79fa2b6187a5e56b1e92bafc7c4cd2.tar.gz
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.
Diffstat (limited to 'src/locale')
-rw-r--r--src/locale/dcngettext.c35
1 files 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--) {