summaryrefslogtreecommitdiff
path: root/system/musl/dcngettext-null-deref.patch
blob: bcc385e865fa465cf4da8e8a670c988a4cf42769 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
From 017e67ddde79fa2b6187a5e56b1e92bafc7c4cd2 Mon Sep 17 00:00:00 2001
From: Rich Felker <dalias@aerifal.cx>
Date: Fri, 14 Sep 2018 13:00:41 -0400
Subject: 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--) {
-- 
cgit v1.2.1