1
2
3
4
5 package ld
6
7 import (
8 "debug/pe"
9 "fmt"
10 "internal/testenv"
11 "io/ioutil"
12 "os/exec"
13 "path/filepath"
14 "runtime"
15 "strings"
16 "testing"
17 )
18
19 func TestUndefinedRelocErrors(t *testing.T) {
20 testenv.MustHaveGoBuild(t)
21
22
23
24 testenv.MustInternalLink(t)
25
26 t.Parallel()
27
28 out, err := exec.Command(testenv.GoToolPath(t), "build", "./testdata/issue10978").CombinedOutput()
29 if err == nil {
30 t.Fatal("expected build to fail")
31 }
32
33 wantErrors := map[string]int{
34
35 "function main is undeclared in the main package": 1,
36
37
38
39
40 "main.defined1: relocation target main.undefined not defined": 1,
41 "main.defined2: relocation target main.undefined not defined": 1,
42 }
43 unexpectedErrors := map[string]int{}
44
45 for _, l := range strings.Split(string(out), "\n") {
46 if strings.HasPrefix(l, "#") || l == "" {
47 continue
48 }
49 matched := ""
50 for want := range wantErrors {
51 if strings.Contains(l, want) {
52 matched = want
53 break
54 }
55 }
56 if matched != "" {
57 wantErrors[matched]--
58 } else {
59 unexpectedErrors[l]++
60 }
61 }
62
63 for want, n := range wantErrors {
64 switch {
65 case n > 0:
66 t.Errorf("unmatched error: %s (x%d)", want, n)
67 case n < 0:
68 t.Errorf("extra errors: %s (x%d)", want, -n)
69 }
70 }
71 for unexpected, n := range unexpectedErrors {
72 t.Errorf("unexpected error: %s (x%d)", unexpected, n)
73 }
74 }
75
76 const carchiveSrcText = `
77 package main
78
79 //export GoFunc
80 func GoFunc() {
81 println(42)
82 }
83
84 func main() {
85 }
86 `
87
88 func TestArchiveBuildInvokeWithExec(t *testing.T) {
89 t.Parallel()
90 testenv.MustHaveGoBuild(t)
91 testenv.MustHaveCGO(t)
92
93
94
95 pair := runtime.GOOS + "-" + runtime.GOARCH
96 switch pair {
97 case "darwin-amd64", "darwin-arm64", "linux-amd64", "freebsd-amd64":
98 default:
99 t.Skip("no need for test on " + pair)
100 }
101 switch runtime.GOOS {
102 case "openbsd", "windows":
103 t.Skip("c-archive unsupported")
104 }
105 dir := t.TempDir()
106
107 srcfile := filepath.Join(dir, "test.go")
108 arfile := filepath.Join(dir, "test.a")
109 if err := ioutil.WriteFile(srcfile, []byte(carchiveSrcText), 0666); err != nil {
110 t.Fatal(err)
111 }
112
113 ldf := fmt.Sprintf("-ldflags=-v -tmpdir=%s", dir)
114 argv := []string{"build", "-buildmode=c-archive", "-o", arfile, ldf, srcfile}
115 out, err := exec.Command(testenv.GoToolPath(t), argv...).CombinedOutput()
116 if err != nil {
117 t.Fatalf("build failure: %s\n%s\n", err, string(out))
118 }
119
120 found := false
121 const want = "invoking archiver with syscall.Exec"
122 for _, l := range strings.Split(string(out), "\n") {
123 if strings.HasPrefix(l, want) {
124 found = true
125 break
126 }
127 }
128
129 if !found {
130 t.Errorf("expected '%s' in -v output, got:\n%s\n", want, string(out))
131 }
132 }
133
134 func TestLargeTextSectionSplitting(t *testing.T) {
135 switch runtime.GOARCH {
136 case "ppc64", "ppc64le":
137 case "arm64":
138 if runtime.GOOS == "darwin" {
139 break
140 }
141 fallthrough
142 default:
143 t.Skipf("text section splitting is not done in %s/%s", runtime.GOOS, runtime.GOARCH)
144 }
145
146 testenv.MustHaveGoBuild(t)
147 testenv.MustHaveCGO(t)
148 t.Parallel()
149 dir := t.TempDir()
150
151
152
153
154
155
156 exe := filepath.Join(dir, "go.exe")
157 out, eerr := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, "-ldflags=-linkmode=external -debugtextsize=1048576", "cmd/go").CombinedOutput()
158 if eerr != nil {
159 t.Fatalf("build failure: %s\n%s\n", eerr, string(out))
160 }
161
162
163 _, err := exec.Command(exe, "version").CombinedOutput()
164 if err != nil {
165 t.Fatal(err)
166 }
167 }
168
169 func TestWindowsBuildmodeCSharedASLR(t *testing.T) {
170 platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH)
171 switch platform {
172 case "windows/amd64", "windows/386":
173 default:
174 t.Skip("skipping windows amd64/386 only test")
175 }
176
177 testenv.MustHaveCGO(t)
178
179 t.Run("aslr", func(t *testing.T) {
180 testWindowsBuildmodeCSharedASLR(t, true)
181 })
182 t.Run("no-aslr", func(t *testing.T) {
183 testWindowsBuildmodeCSharedASLR(t, false)
184 })
185 }
186
187 func testWindowsBuildmodeCSharedASLR(t *testing.T, useASLR bool) {
188 t.Parallel()
189 testenv.MustHaveGoBuild(t)
190
191 dir := t.TempDir()
192
193 srcfile := filepath.Join(dir, "test.go")
194 objfile := filepath.Join(dir, "test.dll")
195 if err := ioutil.WriteFile(srcfile, []byte(`package main; func main() { print("hello") }`), 0666); err != nil {
196 t.Fatal(err)
197 }
198 argv := []string{"build", "-buildmode=c-shared"}
199 if !useASLR {
200 argv = append(argv, "-ldflags", "-aslr=false")
201 }
202 argv = append(argv, "-o", objfile, srcfile)
203 out, err := exec.Command(testenv.GoToolPath(t), argv...).CombinedOutput()
204 if err != nil {
205 t.Fatalf("build failure: %s\n%s\n", err, string(out))
206 }
207
208 f, err := pe.Open(objfile)
209 if err != nil {
210 t.Fatal(err)
211 }
212 defer f.Close()
213 var dc uint16
214 switch oh := f.OptionalHeader.(type) {
215 case *pe.OptionalHeader32:
216 dc = oh.DllCharacteristics
217 case *pe.OptionalHeader64:
218 dc = oh.DllCharacteristics
219 hasHEVA := (dc & pe.IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) != 0
220 if useASLR && !hasHEVA {
221 t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag is not set")
222 } else if !useASLR && hasHEVA {
223 t.Error("IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA flag should not be set")
224 }
225 default:
226 t.Fatalf("unexpected optional header type of %T", f.OptionalHeader)
227 }
228 hasASLR := (dc & pe.IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) != 0
229 if useASLR && !hasASLR {
230 t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag is not set")
231 } else if !useASLR && hasASLR {
232 t.Error("IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE flag should not be set")
233 }
234 }
235
236
237
238
239
240
241 func TestMemProfileCheck(t *testing.T) {
242 testenv.MustHaveGoBuild(t)
243 t.Parallel()
244
245 tests := []struct {
246 name string
247 prog string
248 wantOut string
249 }{
250 {
251 "no_memprofile",
252 `
253 package main
254 import "runtime"
255 func main() {
256 println(runtime.MemProfileRate)
257 }
258 `,
259 "0",
260 },
261 {
262 "with_memprofile",
263 `
264 package main
265 import "runtime"
266 func main() {
267 runtime.MemProfile(nil, false)
268 println(runtime.MemProfileRate)
269 }
270 `,
271 "524288",
272 },
273 {
274 "with_memprofile_indirect",
275 `
276 package main
277 import "runtime"
278 var f = runtime.MemProfile
279 func main() {
280 if f == nil {
281 panic("no f")
282 }
283 println(runtime.MemProfileRate)
284 }
285 `,
286 "524288",
287 },
288 {
289 "with_memprofile_runtime_pprof",
290 `
291 package main
292 import "runtime"
293 import "runtime/pprof"
294 func main() {
295 _ = pprof.Profiles()
296 println(runtime.MemProfileRate)
297 }
298 `,
299 "524288",
300 },
301 {
302 "with_memprofile_http_pprof",
303 `
304 package main
305 import "runtime"
306 import _ "net/http/pprof"
307 func main() {
308 println(runtime.MemProfileRate)
309 }
310 `,
311 "524288",
312 },
313 }
314 for _, tt := range tests {
315 tt := tt
316 t.Run(tt.name, func(t *testing.T) {
317 t.Parallel()
318 tempDir := t.TempDir()
319 src := filepath.Join(tempDir, "x.go")
320 if err := ioutil.WriteFile(src, []byte(tt.prog), 0644); err != nil {
321 t.Fatal(err)
322 }
323 cmd := exec.Command(testenv.GoToolPath(t), "run", src)
324 out, err := cmd.CombinedOutput()
325 if err != nil {
326 t.Fatal(err)
327 }
328 got := strings.TrimSpace(string(out))
329 if got != tt.wantOut {
330 t.Errorf("got %q; want %q", got, tt.wantOut)
331 }
332 })
333 }
334 }
335
View as plain text