diff options
| author | Junyang Shao <shaojunyang@google.com> | 2026-03-12 21:36:33 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-04-07 12:14:04 -0700 |
| commit | 3a4577a2687ad46d2a00305ddb68733283ea0720 (patch) | |
| tree | c5708800a5e49313c96a3265a2d8074178f4f9b4 | |
| parent | ceb4da6626ce94d75b2aefd0f24c6d0fd74f45f9 (diff) | |
| download | go-3a4577a2687ad46d2a00305ddb68733283ea0720.tar.xz | |
[release-branch.go1.26] cmd/compile: fix mem access overlap detection
When a no-op interface conversion is wrapped around the rhs of an
assignment, the memory overlap detection logic in the compiler failed to
peel down conversion to see the actual pointer, causing an incorrect
no-overlapping determination.
Thanks to Jakub Ciolek for reporting this issue.
Fixes #78371
Fixes CVE-2026-27144
Change-Id: I55ff0806b099e1447bdbfba7fde6c6597db5d65c
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/3780
Reviewed-by: Damien Neil <dneil@google.com>
Reviewed-by: Neal Patel <nealpatel@google.com>
Reviewed-on: https://go-internal-review.googlesource.com/c/go/+/4001
Commit-Queue: Damien Neil <dneil@google.com>
Reviewed-on: https://go-review.googlesource.com/c/go/+/763545
TryBot-Bypass: Gopher Robot <gobot@golang.org>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: David Chase <drchase@google.com>
Auto-Submit: Gopher Robot <gobot@golang.org>
| -rw-r--r-- | src/cmd/compile/internal/ssagen/ssa.go | 20 | ||||
| -rw-r--r-- | src/cmd/compile/internal/test/memoverlap_test.go | 41 |
2 files changed, 55 insertions, 6 deletions
diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 849781c9ee..3da43e715e 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -1653,6 +1653,16 @@ func (s *state) stmtList(l ir.Nodes) { } } +func peelConvNop(n ir.Node) ir.Node { + if n == nil { + return n + } + for n.Op() == ir.OCONVNOP { + n = n.(*ir.ConvExpr).X + } + return n +} + // stmt converts the statement n to SSA and adds it to s. func (s *state) stmt(n ir.Node) { s.pushLine(n.Pos()) @@ -1828,12 +1838,10 @@ func (s *state) stmt(n ir.Node) { // arrays referenced are strictly smaller parts of the same base array. // If one side of the assignment is a full array, then partial overlap // can't happen. (The arrays are either disjoint or identical.) - mayOverlap := n.X.Op() == ir.ODEREF && (n.Y != nil && n.Y.Op() == ir.ODEREF) - if n.Y != nil && n.Y.Op() == ir.ODEREF { - p := n.Y.(*ir.StarExpr).X - for p.Op() == ir.OCONVNOP { - p = p.(*ir.ConvExpr).X - } + ny := peelConvNop(n.Y) + mayOverlap := n.X.Op() == ir.ODEREF && (n.Y != nil && ny.Op() == ir.ODEREF) + if ny != nil && ny.Op() == ir.ODEREF { + p := peelConvNop(ny.(*ir.StarExpr).X) if p.Op() == ir.OSPTR && p.(*ir.UnaryExpr).X.Type().IsString() { // Pointer fields of strings point to unmodifiable memory. // That memory can't overlap with the memory being written. diff --git a/src/cmd/compile/internal/test/memoverlap_test.go b/src/cmd/compile/internal/test/memoverlap_test.go new file mode 100644 index 0000000000..c53288e6bb --- /dev/null +++ b/src/cmd/compile/internal/test/memoverlap_test.go @@ -0,0 +1,41 @@ +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package test + +import "testing" + +const arrFooSize = 96 + +type arrFoo [arrFooSize]int + +//go:noinline +func badCopy(dst, src []int) { + p := (*[arrFooSize]int)(dst[:arrFooSize]) + q := (*[arrFooSize]int)(src[:arrFooSize]) + *p = arrFoo(*q) +} + +//go:noinline +func goodCopy(dst, src []int) { + p := (*[arrFooSize]int)(dst[:arrFooSize]) + q := (*[arrFooSize]int)(src[:arrFooSize]) + *p = *q +} + +func TestOverlapedMoveWithNoopIConv(t *testing.T) { + h1 := make([]int, arrFooSize+1) + h2 := make([]int, arrFooSize+1) + for i := range arrFooSize + 1 { + h1[i] = i + h2[i] = i + } + badCopy(h1[1:], h1[:arrFooSize]) + goodCopy(h2[1:], h2[:arrFooSize]) + for i := range arrFooSize + 1 { + if h1[i] != h2[i] { + t.Errorf("h1 and h2 differ at index %d, expect them to be the same", i) + } + } +} |
