blob: 5ea9cbd88a125f01020f1a2950eac7c3ef40b666 [file] [log] [blame]
Dan Willemsen38f2dba2016-07-08 14:54:35 -07001// Copyright 2012 The Go Authors. All rights reserved.
Brent Austinba3052e2015-04-21 16:08:23 -07002// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime_test
6
7import (
Dan Willemsena3223282018-02-27 19:41:43 -08008 "flag"
Brent Austinba3052e2015-04-21 16:08:23 -07009 "io"
Brent Austinba3052e2015-04-21 16:08:23 -070010 . "runtime"
11 "runtime/debug"
Dan Willemsenebae3022017-01-13 23:01:08 -080012 "strings"
Brent Austinba3052e2015-04-21 16:08:23 -070013 "testing"
14 "unsafe"
15)
16
Dan Willemsena3223282018-02-27 19:41:43 -080017var flagQuick = flag.Bool("quick", false, "skip slow tests, for second run in all.bash")
18
Dan Willemsen38f2dba2016-07-08 14:54:35 -070019func init() {
20 // We're testing the runtime, so make tracebacks show things
21 // in the runtime. This only raises the level, so it won't
22 // override GOTRACEBACK=crash from the user.
23 SetTracebackEnv("system")
24}
25
Brent Austinba3052e2015-04-21 16:08:23 -070026var errf error
27
28func errfn() error {
29 return errf
30}
31
32func errfn1() error {
33 return io.EOF
34}
35
36func BenchmarkIfaceCmp100(b *testing.B) {
37 for i := 0; i < b.N; i++ {
38 for j := 0; j < 100; j++ {
39 if errfn() == io.EOF {
40 b.Fatal("bad comparison")
41 }
42 }
43 }
44}
45
46func BenchmarkIfaceCmpNil100(b *testing.B) {
47 for i := 0; i < b.N; i++ {
48 for j := 0; j < 100; j++ {
49 if errfn1() == nil {
50 b.Fatal("bad comparison")
51 }
52 }
53 }
54}
55
Dan Willemsend2797482017-07-26 13:13:13 -070056var efaceCmp1 interface{}
57var efaceCmp2 interface{}
58
59func BenchmarkEfaceCmpDiff(b *testing.B) {
60 x := 5
61 efaceCmp1 = &x
62 y := 6
63 efaceCmp2 = &y
64 for i := 0; i < b.N; i++ {
65 for j := 0; j < 100; j++ {
66 if efaceCmp1 == efaceCmp2 {
67 b.Fatal("bad comparison")
68 }
69 }
70 }
71}
72
Colin Cross430342c2019-09-07 08:36:04 -070073func BenchmarkEfaceCmpDiffIndirect(b *testing.B) {
74 efaceCmp1 = [2]int{1, 2}
75 efaceCmp2 = [2]int{1, 2}
76 for i := 0; i < b.N; i++ {
77 for j := 0; j < 100; j++ {
78 if efaceCmp1 != efaceCmp2 {
79 b.Fatal("bad comparison")
80 }
81 }
82 }
83}
84
Brent Austinba3052e2015-04-21 16:08:23 -070085func BenchmarkDefer(b *testing.B) {
86 for i := 0; i < b.N; i++ {
87 defer1()
88 }
89}
90
91func defer1() {
92 defer func(x, y, z int) {
93 if recover() != nil || x != 1 || y != 2 || z != 3 {
94 panic("bad recover")
95 }
96 }(1, 2, 3)
Brent Austinba3052e2015-04-21 16:08:23 -070097}
98
99func BenchmarkDefer10(b *testing.B) {
100 for i := 0; i < b.N/10; i++ {
101 defer2()
102 }
103}
104
105func defer2() {
106 for i := 0; i < 10; i++ {
107 defer func(x, y, z int) {
108 if recover() != nil || x != 1 || y != 2 || z != 3 {
109 panic("bad recover")
110 }
111 }(1, 2, 3)
112 }
113}
114
115func BenchmarkDeferMany(b *testing.B) {
116 for i := 0; i < b.N; i++ {
117 defer func(x, y, z int) {
118 if recover() != nil || x != 1 || y != 2 || z != 3 {
119 panic("bad recover")
120 }
121 }(1, 2, 3)
122 }
123}
124
Brent Austinba3052e2015-04-21 16:08:23 -0700125// golang.org/issue/7063
126func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
127 SetCPUProfileRate(0)
128}
129
130// Addresses to test for faulting behavior.
131// This is less a test of SetPanicOnFault and more a check that
132// the operating system and the runtime can process these faults
133// correctly. That is, we're indirectly testing that without SetPanicOnFault
134// these would manage to turn into ordinary crashes.
135// Note that these are truncated on 32-bit systems, so the bottom 32 bits
136// of the larger addresses must themselves be invalid addresses.
137// We might get unlucky and the OS might have mapped one of these
138// addresses, but probably not: they're all in the first page, very high
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700139// addresses that normally an OS would reserve for itself, or malformed
Brent Austinba3052e2015-04-21 16:08:23 -0700140// addresses. Even so, we might have to remove one or two on different
141// systems. We will see.
142
143var faultAddrs = []uint64{
144 // low addresses
145 0,
146 1,
147 0xfff,
148 // high (kernel) addresses
149 // or else malformed.
150 0xffffffffffffffff,
151 0xfffffffffffff001,
152 0xffffffffffff0001,
153 0xfffffffffff00001,
154 0xffffffffff000001,
155 0xfffffffff0000001,
156 0xffffffff00000001,
157 0xfffffff000000001,
158 0xffffff0000000001,
159 0xfffff00000000001,
160 0xffff000000000001,
161 0xfff0000000000001,
162 0xff00000000000001,
163 0xf000000000000001,
164 0x8000000000000001,
165}
166
167func TestSetPanicOnFault(t *testing.T) {
Brent Austinba3052e2015-04-21 16:08:23 -0700168 old := debug.SetPanicOnFault(true)
169 defer debug.SetPanicOnFault(old)
170
171 nfault := 0
172 for _, addr := range faultAddrs {
173 testSetPanicOnFault(t, uintptr(addr), &nfault)
174 }
175 if nfault == 0 {
176 t.Fatalf("none of the addresses faulted")
177 }
178}
179
180func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) {
181 if GOOS == "nacl" {
182 t.Skip("nacl doesn't seem to fault on high addresses")
183 }
Dan Willemsenc7413322018-08-27 23:21:26 -0700184 if GOOS == "js" {
185 t.Skip("js does not support catching faults")
186 }
Brent Austinba3052e2015-04-21 16:08:23 -0700187
188 defer func() {
189 if err := recover(); err != nil {
190 *nfault++
191 }
192 }()
193
194 // The read should fault, except that sometimes we hit
195 // addresses that have had C or kernel pages mapped there
196 // readable by user code. So just log the content.
197 // If no addresses fault, we'll fail the test.
198 v := *(*byte)(unsafe.Pointer(addr))
199 t.Logf("addr %#x: %#x\n", addr, v)
200}
201
202func eqstring_generic(s1, s2 string) bool {
203 if len(s1) != len(s2) {
204 return false
205 }
206 // optimization in assembly versions:
207 // if s1.str == s2.str { return true }
208 for i := 0; i < len(s1); i++ {
209 if s1[i] != s2[i] {
210 return false
211 }
212 }
213 return true
214}
215
216func TestEqString(t *testing.T) {
Dan Willemsena3223282018-02-27 19:41:43 -0800217 // This isn't really an exhaustive test of == on strings, it's
Brent Austinba3052e2015-04-21 16:08:23 -0700218 // just a convenient way of documenting (via eqstring_generic)
Dan Willemsena3223282018-02-27 19:41:43 -0800219 // what == does.
Brent Austinba3052e2015-04-21 16:08:23 -0700220 s := []string{
221 "",
222 "a",
223 "c",
224 "aaa",
225 "ccc",
226 "cccc"[:3], // same contents, different string
227 "1234567890",
228 }
229 for _, s1 := range s {
230 for _, s2 := range s {
231 x := s1 == s2
232 y := eqstring_generic(s1, s2)
233 if x != y {
Dan Willemsena3223282018-02-27 19:41:43 -0800234 t.Errorf(`("%s" == "%s") = %t, want %t`, s1, s2, x, y)
Brent Austinba3052e2015-04-21 16:08:23 -0700235 }
236 }
237 }
238}
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700239
240func TestTrailingZero(t *testing.T) {
241 // make sure we add padding for structs with trailing zero-sized fields
242 type T1 struct {
243 n int32
244 z [0]byte
245 }
246 if unsafe.Sizeof(T1{}) != 8 {
247 t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{}))
248 }
249 type T2 struct {
250 n int64
251 z struct{}
252 }
253 if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(Uintreg(0)) {
254 t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(Uintreg(0)))
255 }
256 type T3 struct {
257 n byte
258 z [4]struct{}
259 }
260 if unsafe.Sizeof(T3{}) != 2 {
261 t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{}))
262 }
263 // make sure padding can double for both zerosize and alignment
264 type T4 struct {
265 a int32
266 b int16
267 c int8
268 z struct{}
269 }
270 if unsafe.Sizeof(T4{}) != 8 {
271 t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{}))
272 }
273 // make sure we don't pad a zero-sized thing
274 type T5 struct {
275 }
276 if unsafe.Sizeof(T5{}) != 0 {
277 t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{}))
278 }
279}
280
281func TestBadOpen(t *testing.T) {
Dan Willemsenc7413322018-08-27 23:21:26 -0700282 if GOOS == "windows" || GOOS == "nacl" || GOOS == "js" {
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700283 t.Skip("skipping OS that doesn't have open/read/write/close")
284 }
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700285 // make sure we get the correct error code if open fails. Same for
286 // read/write/close on the resulting -1 fd. See issue 10052.
Dan Willemsen09eb3b12015-09-16 14:34:17 -0700287 nonfile := []byte("/notreallyafile")
288 fd := Open(&nonfile[0], 0, 0)
289 if fd != -1 {
290 t.Errorf("open(\"%s\")=%d, want -1", string(nonfile), fd)
291 }
292 var buf [32]byte
293 r := Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf)))
294 if r != -1 {
295 t.Errorf("read()=%d, want -1", r)
296 }
297 w := Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf)))
298 if w != -1 {
299 t.Errorf("write()=%d, want -1", w)
300 }
301 c := Close(-1)
302 if c != -1 {
303 t.Errorf("close()=%d, want -1", c)
304 }
305}
306
307func TestAppendGrowth(t *testing.T) {
308 var x []int64
309 check := func(want int) {
310 if cap(x) != want {
311 t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
312 }
313 }
314
315 check(0)
316 want := 1
317 for i := 1; i <= 100; i++ {
318 x = append(x, 1)
319 check(want)
320 if i&(i-1) == 0 {
321 want = 2 * i
322 }
323 }
324}
325
326var One = []int64{1}
327
328func TestAppendSliceGrowth(t *testing.T) {
329 var x []int64
330 check := func(want int) {
331 if cap(x) != want {
332 t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
333 }
334 }
335
336 check(0)
337 want := 1
338 for i := 1; i <= 100; i++ {
339 x = append(x, One...)
340 check(want)
341 if i&(i-1) == 0 {
342 want = 2 * i
343 }
344 }
345}
Dan Willemsen38f2dba2016-07-08 14:54:35 -0700346
347func TestGoroutineProfileTrivial(t *testing.T) {
348 // Calling GoroutineProfile twice in a row should find the same number of goroutines,
349 // but it's possible there are goroutines just about to exit, so we might end up
350 // with fewer in the second call. Try a few times; it should converge once those
351 // zombies are gone.
352 for i := 0; ; i++ {
353 n1, ok := GoroutineProfile(nil) // should fail, there's at least 1 goroutine
354 if n1 < 1 || ok {
355 t.Fatalf("GoroutineProfile(nil) = %d, %v, want >0, false", n1, ok)
356 }
357 n2, ok := GoroutineProfile(make([]StackRecord, n1))
358 if n2 == n1 && ok {
359 break
360 }
361 t.Logf("GoroutineProfile(%d) = %d, %v, want %d, true", n1, n2, ok, n1)
362 if i >= 10 {
363 t.Fatalf("GoroutineProfile not converging")
364 }
365 }
366}
Dan Willemsenebae3022017-01-13 23:01:08 -0800367
368func TestVersion(t *testing.T) {
369 // Test that version does not contain \r or \n.
370 vers := Version()
371 if strings.Contains(vers, "\r") || strings.Contains(vers, "\n") {
372 t.Fatalf("cr/nl in version: %q", vers)
373 }
374}