Skip to content

Commit 86e65b8

Browse files
TimothyGuneild
authored andcommitted
internal/export/idna: fix int32 overflows
Prefer multiplication (int64(b)*int64(c) > MaxInt32) over division (b > MaxInt32/c) for overflow checking as it is a little faster on 386, and a LOT faster on amd64. For golang/go#28233. Change-Id: Ibf42529b93b699417781adc7eca6e66474f00bbf Reviewed-on: https://go-review.googlesource.com/c/text/+/317731 Run-TryBot: Ian Lance Taylor <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Trust: Damien Neil <[email protected]>
1 parent bb1c798 commit 86e65b8

File tree

2 files changed

+26
-11
lines changed

2 files changed

+26
-11
lines changed

internal/export/idna/punycode.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func decode(encoded string) (string, error) {
4747
}
4848
}
4949
i, n, bias := int32(0), initialN, initialBias
50+
overflow := false
5051
for pos < len(encoded) {
5152
oldI, w := i, int32(1)
5253
for k := base; ; k += base {
@@ -58,29 +59,32 @@ func decode(encoded string) (string, error) {
5859
return "", punyError(encoded)
5960
}
6061
pos++
61-
i += digit * w
62-
if i < 0 {
62+
i, overflow = madd(i, digit, w)
63+
if overflow {
6364
return "", punyError(encoded)
6465
}
6566
t := k - bias
66-
if t < tmin {
67+
if k <= bias {
6768
t = tmin
68-
} else if t > tmax {
69+
} else if k >= bias+tmax {
6970
t = tmax
7071
}
7172
if digit < t {
7273
break
7374
}
74-
w *= base - t
75-
if w >= math.MaxInt32/base {
75+
w, overflow = madd(0, w, base-t)
76+
if overflow {
7677
return "", punyError(encoded)
7778
}
7879
}
80+
if len(output) >= 1024 {
81+
return "", punyError(encoded)
82+
}
7983
x := int32(len(output) + 1)
8084
bias = adapt(i-oldI, x, oldI == 0)
8185
n += i / x
8286
i %= x
83-
if n > utf8.MaxRune || len(output) >= 1024 {
87+
if n < 0 || n > utf8.MaxRune {
8488
return "", punyError(encoded)
8589
}
8690
output = append(output, 0)
@@ -113,15 +117,16 @@ func encode(prefix, s string) (string, error) {
113117
if b > 0 {
114118
output = append(output, '-')
115119
}
120+
overflow := false
116121
for remaining != 0 {
117122
m := int32(0x7fffffff)
118123
for _, r := range s {
119124
if m > r && r >= n {
120125
m = r
121126
}
122127
}
123-
delta += (m - n) * (h + 1)
124-
if delta < 0 {
128+
delta, overflow = madd(delta, m-n, h+1)
129+
if overflow {
125130
return "", punyError(s)
126131
}
127132
n = m
@@ -139,9 +144,9 @@ func encode(prefix, s string) (string, error) {
139144
q := delta
140145
for k := base; ; k += base {
141146
t := k - bias
142-
if t < tmin {
147+
if k <= bias {
143148
t = tmin
144-
} else if t > tmax {
149+
} else if k >= bias+tmax {
145150
t = tmax
146151
}
147152
if q < t {
@@ -162,6 +167,15 @@ func encode(prefix, s string) (string, error) {
162167
return string(output), nil
163168
}
164169

170+
// madd computes a + (b * c), detecting overflow.
171+
func madd(a, b, c int32) (next int32, overflow bool) {
172+
p := int64(b) * int64(c)
173+
if p > math.MaxInt32-int64(a) {
174+
return 0, true
175+
}
176+
return a + int32(p), false
177+
}
178+
165179
func decodeDigit(x byte) (digit int32, ok bool) {
166180
switch {
167181
case '0' <= x && x <= '9':

internal/export/idna/punycode_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ var punycodeErrorTestCases = [...]string{
177177
"decode 9999999999a", // "9999999999a" overflows the int32 calculation.
178178

179179
"encode " + strings.Repeat("x", 65536) + "\uff00", // int32 overflow.
180+
"encode " + strings.Repeat("x", 65666) + "\uffff", // int32 overflow. issue #28233
180181
}
181182

182183
func TestPunycodeErrors(t *testing.T) {

0 commit comments

Comments
 (0)