aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2018-12-20 20:21:45 +0000
committerAndrew Bonventre <andybons@golang.org>2019-03-14 19:33:12 +0000
commit6e6462315b628bc364bbdf68da64322763f17b81 (patch)
tree76b53a2906995f0c41cad70480d08c0a3e08062e
parent6a7a8ba07fb22b006fb1af4c9413d20f0257a32e (diff)
downloadgo-6e6462315b628bc364bbdf68da64322763f17b81.tar.gz
go-6e6462315b628bc364bbdf68da64322763f17b81.zip
[release-branch.go1.11] runtime: skip TestLockOSThreadAvoidsStatePropagation if one can't unshare
This change splits a testprog out of TestLockOSThreadExit and makes it its own test. Then, this change makes the testprog exit prematurely with a special message if unshare fails with EPERM because not all of the builders allow the user to call the unshare syscall. Also, do some minor cleanup on the TestLockOSThread* tests. Fixes #29366. Change-Id: Id8a9f6c4b16e26af92ed2916b90b0249ba226dbe Reviewed-on: https://go-review.googlesource.com/c/155437 Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> (cherry picked from commit 429bae715876c69853bb63db1733f580e293c916) Reviewed-on: https://go-review.googlesource.com/c/go/+/167707 Run-TryBot: Andrew Bonventre <andybons@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
-rw-r--r--src/runtime/proc_test.go21
-rw-r--r--src/runtime/testdata/testprog/lockosthread.go4
-rw-r--r--src/runtime/testdata/testprog/syscalls.go47
-rw-r--r--src/runtime/testdata/testprog/syscalls_linux.go59
4 files changed, 78 insertions, 53 deletions
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index e6947d5849..1715324aa0 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -885,23 +885,28 @@ func TestLockOSThreadNesting(t *testing.T) {
func TestLockOSThreadExit(t *testing.T) {
testLockOSThreadExit(t, "testprog")
-
- want := "OK\n"
- output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
- if output != want {
- t.Errorf("want %s, got %s\n", want, output)
- }
}
func testLockOSThreadExit(t *testing.T, prog string) {
output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1")
want := "OK\n"
if output != want {
- t.Errorf("want %s, got %s\n", want, output)
+ t.Errorf("want %q, got %q", want, output)
}
output = runTestProg(t, prog, "LockOSThreadAlt")
if output != want {
- t.Errorf("want %s, got %s\n", want, output)
+ t.Errorf("want %q, got %q", want, output)
+ }
+}
+
+func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
+ want := "OK\n"
+ skip := "unshare not permitted\n"
+ output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
+ if output == skip {
+ t.Skip("unshare syscall not permitted on this system")
+ } else if output != want {
+ t.Errorf("want %q, got %q", want, output)
}
}
diff --git a/src/runtime/testdata/testprog/lockosthread.go b/src/runtime/testdata/testprog/lockosthread.go
index 5119cf8131..fd3123e647 100644
--- a/src/runtime/testdata/testprog/lockosthread.go
+++ b/src/runtime/testdata/testprog/lockosthread.go
@@ -144,6 +144,10 @@ func LockOSThreadAvoidsStatePropagation() {
// the rest of the process on this thread.
// On systems other than Linux, this is a no-op.
if err := unshareFs(); err != nil {
+ if err == errNotPermitted {
+ println("unshare not permitted")
+ os.Exit(0)
+ }
println("failed to unshare fs:", err.Error())
os.Exit(1)
}
diff --git a/src/runtime/testdata/testprog/syscalls.go b/src/runtime/testdata/testprog/syscalls.go
index 08284fc561..098d5cadf8 100644
--- a/src/runtime/testdata/testprog/syscalls.go
+++ b/src/runtime/testdata/testprog/syscalls.go
@@ -2,53 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux
-
package main
import (
- "bytes"
- "fmt"
- "io/ioutil"
- "os"
- "syscall"
+ "errors"
)
-func gettid() int {
- return syscall.Gettid()
-}
-
-func tidExists(tid int) (exists, supported bool) {
- stat, err := ioutil.ReadFile(fmt.Sprintf("/proc/self/task/%d/stat", tid))
- if os.IsNotExist(err) {
- return false, true
- }
- // Check if it's a zombie thread.
- state := bytes.Fields(stat)[2]
- return !(len(state) == 1 && state[0] == 'Z'), true
-}
-
-func getcwd() (string, error) {
- if !syscall.ImplementsGetwd {
- return "", nil
- }
- // Use the syscall to get the current working directory.
- // This is imperative for checking for OS thread state
- // after an unshare since os.Getwd might just check the
- // environment, or use some other mechanism.
- var buf [4096]byte
- n, err := syscall.Getcwd(buf[:])
- if err != nil {
- return "", err
- }
- // Subtract one for null terminator.
- return string(buf[:n-1]), nil
-}
-
-func unshareFs() error {
- return syscall.Unshare(syscall.CLONE_FS)
-}
-
-func chdir(path string) error {
- return syscall.Chdir(path)
-}
+var errNotPermitted = errors.New("operation not permitted")
diff --git a/src/runtime/testdata/testprog/syscalls_linux.go b/src/runtime/testdata/testprog/syscalls_linux.go
new file mode 100644
index 0000000000..b8ac087626
--- /dev/null
+++ b/src/runtime/testdata/testprog/syscalls_linux.go
@@ -0,0 +1,59 @@
+// Copyright 2017 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 (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "syscall"
+)
+
+func gettid() int {
+ return syscall.Gettid()
+}
+
+func tidExists(tid int) (exists, supported bool) {
+ stat, err := ioutil.ReadFile(fmt.Sprintf("/proc/self/task/%d/stat", tid))
+ if os.IsNotExist(err) {
+ return false, true
+ }
+ // Check if it's a zombie thread.
+ state := bytes.Fields(stat)[2]
+ return !(len(state) == 1 && state[0] == 'Z'), true
+}
+
+func getcwd() (string, error) {
+ if !syscall.ImplementsGetwd {
+ return "", nil
+ }
+ // Use the syscall to get the current working directory.
+ // This is imperative for checking for OS thread state
+ // after an unshare since os.Getwd might just check the
+ // environment, or use some other mechanism.
+ var buf [4096]byte
+ n, err := syscall.Getcwd(buf[:])
+ if err != nil {
+ return "", err
+ }
+ // Subtract one for null terminator.
+ return string(buf[:n-1]), nil
+}
+
+func unshareFs() error {
+ err := syscall.Unshare(syscall.CLONE_FS)
+ if err != nil {
+ errno, ok := err.(syscall.Errno)
+ if ok && errno == syscall.EPERM {
+ return errNotPermitted
+ }
+ }
+ return err
+}
+
+func chdir(path string) error {
+ return syscall.Chdir(path)
+}