[release-branch.go1.15] cmd/link: fix handling of dupok mapzero syms

The compiler machinery that generates "map.zero" symbols marks them as
RODATA and DUPOK, which is problematic when a given application has
multiple map zero symbols (from different packages) with varying
sizes: the dupok path in the loader assumes that if two symbols have
the same name, it is safe to pick any of the versions. In the case of
map.zero, the link needs to select the largest symbol, not an
arbitrary sym.

This patch changes the linker's dupok symbol loading path to detect
this problem, and in situations where we're loading a dupok symbol
whose name is the same as an existing symbol but whose size is large,
select the new dup over the old. Note: this fix differs from the one
used in 1.16/1.17, which uses content-addressable symbols instead.

Fixes #46656.

Change-Id: Iabd2feef01d448670ba795c7eaddc48c191ea276
Reviewed-on: https://go-review.googlesource.com/c/go/+/326211
Trust: Than McIntosh <thanm@google.com>
Run-TryBot: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
(cherry picked from commit aa5540cd82170f82c6fe11511e12de96aa58cbc1)
Reviewed-on: https://go-review.googlesource.com/c/go/+/326213
This commit is contained in:
Than McIntosh 2021-06-08 20:09:49 -04:00 committed by Dmitri Shuralyov
parent 0e7012ef86
commit b51bf4febc
4 changed files with 112 additions and 1 deletions

View File

@ -434,7 +434,17 @@ func (l *Loader) AddSym(name string, ver int, r *oReader, li int, kind int, dupo
if l.flags&FlagStrictDups != 0 {
l.checkdup(name, r, li, oldi)
}
return oldi, false
// Fix for issue #46656 -- given two dupok symbols with
// different sizes, favor symbol with larger size.
szdup := l.SymSize(oldi)
sz := int64(r.Sym(li).Siz())
if szdup >= sz {
return oldi, false
} else {
// new symbol overwrites old symbol.
l.objSyms[oldi] = objSym{r, li}
return oldi, true
}
}
oldr, oldli := l.toLocal(oldi)
oldsym := oldr.Sym(oldli)

View File

@ -0,0 +1,64 @@
// Copyright 2021 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 a
func Bad() {
m := make(map[int64]A)
a := m[0]
if len(a.B.C1.D2.E2.F1) != 0 ||
len(a.B.C1.D2.E2.F2) != 0 ||
len(a.B.C1.D2.E2.F3) != 0 ||
len(a.B.C1.D2.E2.F4) != 0 ||
len(a.B.C1.D2.E2.F5) != 0 ||
len(a.B.C1.D2.E2.F6) != 0 ||
len(a.B.C1.D2.E2.F7) != 0 ||
len(a.B.C1.D2.E2.F8) != 0 ||
len(a.B.C1.D2.E2.F9) != 0 ||
len(a.B.C1.D2.E2.F10) != 0 ||
len(a.B.C1.D2.E2.F11) != 0 ||
len(a.B.C1.D2.E2.F16) != 0 {
panic("bad")
}
}
type A struct {
B
}
type B struct {
C1 C
C2 C
}
type C struct {
D1 D
D2 D
}
type D struct {
E1 E
E2 E
E3 E
E4 E
}
type E struct {
F1 string
F2 string
F3 string
F4 string
F5 string
F6 string
F7 string
F8 string
F9 string
F10 string
F11 string
F12 string
F13 string
F14 string
F15 string
F16 string
}

View File

@ -0,0 +1,27 @@
// Copyright 2021 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 main
import (
bad "issue46653.dir/bad"
)
func main() {
bad.Bad()
}
func neverCalled() L {
m := make(map[string]L)
return m[""]
}
type L struct {
A Data
B Data
}
type Data struct {
F1 [22][]string
}

View File

@ -0,0 +1,10 @@
// runindir
// Copyright 2021 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.
// Test to verify compiler and linker handling of multiple
// competing map.zero symbol definitions.
package ignored