Skip to content

Commit 7d2dd34

Browse files
JunyangShaogopherbot
authored andcommitted
[release-branch.go1.25] cmd/compile: fix loopbce overflow check logic
addWillOverflow and subWillOverflow has an implicit assumption that y is positive, using it outside of addU and subU is really incorrect. This CL fixes those incorrect usage to use the correct logic in place. Thanks to Jakub Ciolek for reporting this issue. Fixes #78333 Fixes CVE-2026-27143 Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3700 Reviewed-by: Damien Neil <dneil@google.com> Reviewed-by: Neal Patel <nealpatel@google.com> Change-Id: I263e8e7ac227e2a68109eb7bbd45f66569ed22ec Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3987 Commit-Queue: Damien Neil <dneil@google.com> Reviewed-on: https://go-review.googlesource.com/c/go/+/763553 Reviewed-by: David Chase <drchase@google.com> Auto-Submit: Gopher Robot <gobot@golang.org> TryBot-Bypass: Gopher Robot <gobot@golang.org> Reviewed-by: Junyang Shao <shaojunyang@google.com>
1 parent 72cc336 commit 7d2dd34

2 files changed

Lines changed: 53 additions & 11 deletions

File tree

src/cmd/compile/internal/ssa/loopbce.go

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,11 @@ func findIndVar(f *Func) []indVar {
204204
if init.AuxInt > v {
205205
return false
206206
}
207+
// TODO(1.27): investigate passing a smaller-magnitude overflow limit to addU
208+
// for addWillOverflow.
207209
v = addU(init.AuxInt, diff(v, init.AuxInt)/uint64(step)*uint64(step))
208210
}
209-
if addWillOverflow(v, step) {
211+
if addWillOverflow(v, step, maxSignedValue(ind.Type)) {
210212
return false
211213
}
212214
if inclusive && v != limit.AuxInt || !inclusive && v+1 != limit.AuxInt {
@@ -235,7 +237,7 @@ func findIndVar(f *Func) []indVar {
235237
// ind < knn - k cannot overflow if step is at most k+1
236238
return step <= k+1 && k != maxSignedValue(limit.Type)
237239
} else { // step < 0
238-
if limit.Op == OpConst64 {
240+
if limit.isGenericIntConst() {
239241
// Figure out the actual smallest value.
240242
v := limit.AuxInt
241243
if !inclusive {
@@ -249,9 +251,11 @@ func findIndVar(f *Func) []indVar {
249251
if init.AuxInt < v {
250252
return false
251253
}
254+
// TODO(1.27): investigate passing a smaller-magnitude underflow limit to subU
255+
// for subWillUnderflow.
252256
v = subU(init.AuxInt, diff(init.AuxInt, v)/uint64(-step)*uint64(-step))
253257
}
254-
if subWillUnderflow(v, -step) {
258+
if subWillUnderflow(v, -step, minSignedValue(ind.Type)) {
255259
return false
256260
}
257261
if inclusive && v != limit.AuxInt || !inclusive && v-1 != limit.AuxInt {
@@ -313,14 +317,22 @@ func findIndVar(f *Func) []indVar {
313317
return iv
314318
}
315319

316-
// addWillOverflow reports whether x+y would result in a value more than maxint.
317-
func addWillOverflow(x, y int64) bool {
318-
return x+y < x
320+
// subWillUnderflow checks if x - y underflows the min value.
321+
// y must be positive.
322+
func subWillUnderflow(x, y int64, min int64) bool {
323+
if y < 0 {
324+
base.Fatalf("expecting positive value")
325+
}
326+
return x < min+y
319327
}
320328

321-
// subWillUnderflow reports whether x-y would result in a value less than minint.
322-
func subWillUnderflow(x, y int64) bool {
323-
return x-y > x
329+
// addWillOverflow checks if x + y overflows the max value.
330+
// y must be positive.
331+
func addWillOverflow(x, y int64, max int64) bool {
332+
if y < 0 {
333+
base.Fatalf("expecting positive value")
334+
}
335+
return x > max-y
324336
}
325337

326338
// diff returns x-y as a uint64. Requires x>=y.
@@ -341,7 +353,8 @@ func addU(x int64, y uint64) int64 {
341353
x += 1
342354
y -= 1 << 63
343355
}
344-
if addWillOverflow(x, int64(y)) {
356+
// TODO(1.27): investigate passing a smaller-magnitude overflow limit in here.
357+
if addWillOverflow(x, int64(y), maxSignedValue(types.Types[types.TINT64])) {
345358
base.Fatalf("addU overflowed %d + %d", x, y)
346359
}
347360
return x + int64(y)
@@ -357,7 +370,8 @@ func subU(x int64, y uint64) int64 {
357370
x -= 1
358371
y -= 1 << 63
359372
}
360-
if subWillUnderflow(x, int64(y)) {
373+
// TODO(1.27): investigate passing a smaller-magnitude underflow limit in here.
374+
if subWillUnderflow(x, int64(y), minSignedValue(types.Types[types.TINT64])) {
361375
base.Fatalf("subU underflowed %d - %d", x, y)
362376
}
363377
return x - int64(y)

test/loopbce.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,34 @@ func stride2(x *[7]int) int {
469469
return s
470470
}
471471

472+
// This loop should not be proved anything.
473+
func smallIntUp(arr *[128]int) {
474+
for i := int8(0); i <= int8(120); i += int8(10) {
475+
arr[i] = int(i)
476+
}
477+
}
478+
479+
// This loop should not be proved anything.
480+
func smallIntDown(arr *[128]int) {
481+
for i := int8(0); i >= int8(-120); i -= int8(10) {
482+
arr[127+i] = int(i)
483+
}
484+
}
485+
486+
// This loop should not be proved anything.
487+
func smallUintUp(arr *[128]int) {
488+
for i := uint8(0); i <= uint8(250); i += uint8(10) {
489+
arr[i] = int(i)
490+
}
491+
}
492+
493+
// This loop should not be proved anything.
494+
func smallUintDown(arr *[128]int) {
495+
for i := uint8(255); i >= uint8(0); i -= uint8(10) {
496+
arr[127+i] = int(i)
497+
}
498+
}
499+
472500
//go:noinline
473501
func useString(a string) {
474502
}

0 commit comments

Comments
 (0)