| // Copyright 2018 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. |
| |
| //go:build darwin && go1.12 |
| // +build darwin,go1.12 |
| |
| package unix |
| |
| import ( |
| "os" |
| "os/exec" |
| "strings" |
| "testing" |
| ) |
| |
| type darwinTest struct { |
| name string |
| f uintptr |
| } |
| |
| // TODO(khr): decide whether to keep this test enabled permanently or |
| // only temporarily. |
| func TestDarwinLoader(t *testing.T) { |
| // Make sure the Darwin dynamic loader can actually resolve |
| // all the system calls into libSystem.dylib. Unfortunately |
| // there is no easy way to test this at compile time. So we |
| // implement a crazy hack here, calling into the syscall |
| // function with all its arguments set to junk, and see what |
| // error we get. We are happy with any error (or none) except |
| // an error from the dynamic loader. |
| // |
| // We have to run each test in a separate subprocess for fault isolation. |
| // |
| // Hopefully the junk args won't accidentally ask the system to do "rm -fr /". |
| // |
| // In an ideal world each syscall would have its own test, so this test |
| // would be unnecessary. Unfortunately, we do not live in that world. |
| for _, test := range darwinTests { |
| // Call the test binary recursively, giving it a magic argument |
| // (see init below) and the name of the test to run. |
| cmd := exec.Command(os.Args[0], "testDarwinLoader", test.name) |
| |
| // Run subprocess, collect results. Note that we expect the subprocess |
| // to fail somehow, so the error is irrelevant. |
| out, _ := cmd.CombinedOutput() |
| |
| if strings.Contains(string(out), "dyld: Symbol not found:") { |
| t.Errorf("can't resolve %s in libSystem.dylib", test.name) |
| } |
| if !strings.Contains(string(out), "success") { |
| // Not really an error. Might be a syscall that never returns, |
| // like exit, or one that segfaults, like gettimeofday. |
| t.Logf("test never finished: %s: %s", test.name, string(out)) |
| } |
| } |
| } |
| |
| func init() { |
| // The test binary execs itself with the "testDarwinLoader" argument. |
| // Run the test specified by os.Args[2], then panic. |
| if len(os.Args) >= 3 && os.Args[1] == "testDarwinLoader" { |
| for _, test := range darwinTests { |
| if test.name == os.Args[2] { |
| syscall_syscall(test.f, ^uintptr(0), ^uintptr(0), ^uintptr(0)) |
| } |
| } |
| // Panic with a "success" label, so the parent process can check it. |
| panic("success") |
| } |
| } |