language: fix off-by-one error

Regions are encoded starting from 1. However, one of the
region-related tables assumed 0-based indices. This
caused a crash when used with ZZ, the largest region.

Fixes golang/go#43834

Change-Id: Iaed6b9d2683cd50504e6d33c8a6df8b21dd1687d
Reviewed-on: https://go-review.googlesource.com/c/text/+/305469
Trust: Marcel van Lohuizen <mpvl@golang.org>
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Seth Vargo <sethvargo@google.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/language/gen.go b/language/gen.go
index 445882e..60bdf64 100644
--- a/language/gen.go
+++ b/language/gen.go
@@ -150,7 +150,9 @@
 		regions := strings.Split(g.Contains, " ")
 		regionHierarchy[g.Type] = append(regionHierarchy[g.Type], regions...)
 	}
-	regionToGroups := make([]uint8, language.NumRegions)
+	// Regions start at 1, so the slice must be one larger than the number of
+	// regions.
+	regionToGroups := make([]uint8, language.NumRegions+1)
 
 	idToIndex := map[string]uint8{}
 	for i, mv := range lm[0].MatchVariable {
diff --git a/language/match_test.go b/language/match_test.go
index c21b863..a6df3e1 100644
--- a/language/match_test.go
+++ b/language/match_test.go
@@ -224,6 +224,20 @@
 	return fmt.Sprintf("%v:%d:%v:%v-%v|%v", t.tag, t.index, t.conf, t.maxRegion, t.maxScript, t.altScript)
 }
 
+func TestIssue43834(t *testing.T) {
+	matcher := NewMatcher([]Tag{English})
+
+	// ZZ is the largest region code and should not cause overflow.
+	desired, _, err := ParseAcceptLanguage("en-ZZ")
+	if err != nil {
+		t.Error(err)
+	}
+	_, i, _ := matcher.Match(desired...)
+	if i != 0 {
+		t.Errorf("got %v; want 0", i)
+	}
+}
+
 func TestBestMatchAlloc(t *testing.T) {
 	m := NewMatcher(makeTagList("en sr nl"))
 	// Go allocates when creating a list of tags from a single tag!
diff --git a/language/tables.go b/language/tables.go
index 87e58a0..96b57f6 100644
--- a/language/tables.go
+++ b/language/tables.go
@@ -47,7 +47,7 @@
 	_Zzzz = 251
 )
 
-var regionToGroups = []uint8{ // 357 elements
+var regionToGroups = []uint8{ // 358 elements
 	// Entry 0 - 3F
 	0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04,
 	0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
@@ -98,8 +98,8 @@
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00,
-} // Size: 381 bytes
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+} // Size: 382 bytes
 
 var paradigmLocales = [][3]uint16{ // 3 elements
 	0: [3]uint16{0x139, 0x0, 0x7b},
@@ -295,4 +295,4 @@
 	14: {lang: 0x529, script: 0x3c, group: 0x80, distance: 0x5},
 } // Size: 114 bytes
 
-// Total table size 1471 bytes (1KiB); checksum: 4CB1CD46
+// Total table size 1472 bytes (1KiB); checksum: F86C669