]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/link: don't reset variable size when handling -X flag
authorCherry Mui <cherryyz@google.com>
Wed, 12 Oct 2022 20:24:34 +0000 (16:24 -0400)
committerCherry Mui <cherryyz@google.com>
Thu, 13 Oct 2022 18:47:30 +0000 (18:47 +0000)
The linker's -X flag allows setting/changing a string variable's
content at link time. Currently it resets its size then write a
new string header pointing to the new content. This mostly works.
But under ASAN build the string variable can have larger size
than the usual 2 words, due to the red zone. Resetting the size
can cause the variable to "overlap" (in ASAN's view) with other
variables. Don't reset the size.

Fixes #56175.

Change-Id: Ib364208201a7a2fd7f44f9b1797834198736a405
Reviewed-on: https://go-review.googlesource.com/c/go/+/442635
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Cherry Mui <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
misc/cgo/testsanitizers/asan_test.go
misc/cgo/testsanitizers/testdata/asan_linkerx/main.go [new file with mode: 0644]
misc/cgo/testsanitizers/testdata/asan_linkerx/p/p.go [new file with mode: 0644]
src/cmd/link/internal/ld/data.go

index 67d097cf161694cef87410b4c4e703f4a6c46e56..932cfb1b6088943b7a6d9ee2c86e315af609343b 100644 (file)
@@ -5,6 +5,7 @@
 package sanitizers_test
 
 import (
+       "fmt"
        "strings"
        "testing"
 )
@@ -97,3 +98,44 @@ func TestASAN(t *testing.T) {
                })
        }
 }
+
+func TestASANLinkerX(t *testing.T) {
+       // Test ASAN with linker's -X flag (see issue 56175).
+       goos, err := goEnv("GOOS")
+       if err != nil {
+               t.Fatal(err)
+       }
+       goarch, err := goEnv("GOARCH")
+       if err != nil {
+               t.Fatal(err)
+       }
+       // The asan tests require support for the -asan option.
+       if !aSanSupported(goos, goarch) {
+               t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
+       }
+       if !compilerRequiredAsanVersion(goos, goarch) {
+               t.Skipf("skipping on %s/%s: too old version of compiler", goos, goarch)
+       }
+
+       t.Parallel()
+       requireOvercommit(t)
+       config := configure("address")
+       config.skipIfCSanitizerBroken(t)
+
+       dir := newTempDir(t)
+       defer dir.RemoveAll(t)
+
+       var ldflags string
+       for i := 1; i <= 10; i++ {
+               ldflags += fmt.Sprintf("-X=main.S%d=%d -X=misc/cgo/testsanitizers/testdata/asan_linkerx/p.S%d=%d ", i, i, i, i)
+       }
+
+       // build the binary
+       outPath := dir.Join("main.exe")
+       cmd := config.goCmd("build", "-ldflags="+ldflags, "-o", outPath)
+       cmd.Dir = srcPath("asan_linkerx")
+       mustRun(t, cmd)
+
+       // run the binary
+       mustRun(t, hangProneCmd(outPath))
+}
diff --git a/misc/cgo/testsanitizers/testdata/asan_linkerx/main.go b/misc/cgo/testsanitizers/testdata/asan_linkerx/main.go
new file mode 100644 (file)
index 0000000..bbd6127
--- /dev/null
@@ -0,0 +1,28 @@
+package main
+
+import "misc/cgo/testsanitizers/testdata/asan_linkerx/p"
+
+func pstring(s *string) {
+       println(*s)
+}
+
+func main() {
+       all := []*string{
+               &S1, &S2, &S3, &S4, &S5, &S6, &S7, &S8, &S9, &S10,
+               &p.S1, &p.S2, &p.S3, &p.S4, &p.S5, &p.S6, &p.S7, &p.S8, &p.S9, &p.S10,
+       }
+       for _, ps := range all {
+               pstring(ps)
+       }
+}
+
+var S1 string
+var S2 string
+var S3 string
+var S4 string
+var S5 string
+var S6 string
+var S7 string
+var S8 string
+var S9 string
+var S10 string
diff --git a/misc/cgo/testsanitizers/testdata/asan_linkerx/p/p.go b/misc/cgo/testsanitizers/testdata/asan_linkerx/p/p.go
new file mode 100644 (file)
index 0000000..c31f001
--- /dev/null
@@ -0,0 +1,12 @@
+package p
+
+var S1 string
+var S2 string
+var S3 string
+var S4 string
+var S5 string
+var S6 string
+var S7 string
+var S8 string
+var S9 string
+var S10 string
index c23eac08a4be2da98c944b6a685c6641652a63b6..1848cd7a5e7f363ffa0d2c29f3a8e9fce70ac60b 100644 (file)
@@ -1127,12 +1127,14 @@ func addstrdata(arch *sys.Arch, l *loader.Loader, name, value string) {
        sbld.Addstring(value)
        sbld.SetType(sym.SRODATA)
 
-       bld.SetSize(0)
-       bld.SetData(make([]byte, 0, arch.PtrSize*2))
+       // Don't reset the variable's size. String variable usually has size of
+       // 2*PtrSize, but in ASAN build it can be larger due to red zone.
+       // (See issue 56175.)
+       bld.SetData(make([]byte, arch.PtrSize*2))
        bld.SetReadOnly(false)
        bld.ResetRelocs()
-       bld.AddAddrPlus(arch, sbld.Sym(), 0)
-       bld.AddUint(arch, uint64(len(value)))
+       bld.SetAddrPlus(arch, 0, sbld.Sym(), 0)
+       bld.SetUint(arch, int64(arch.PtrSize), uint64(len(value)))
 }
 
 func (ctxt *Link) dostrdata() {