• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package tls
6
7import (
8	"bytes"
9	"internal/testenv"
10	"os"
11	"os/exec"
12	"path/filepath"
13	"testing"
14)
15
16// Tests that the linker is able to remove references to the Client or Server if unused.
17func TestLinkerGC(t *testing.T) {
18	if testing.Short() {
19		t.Skip("skipping in short mode")
20	}
21	t.Parallel()
22	goBin := testenv.GoToolPath(t)
23	testenv.MustHaveGoBuild(t)
24
25	tests := []struct {
26		name    string
27		program string
28		want    []string
29		bad     []string
30	}{
31		{
32			name: "empty_import",
33			program: `package main
34import _ "crypto/tls"
35func main() {}
36`,
37			bad: []string{
38				"tls.(*Conn)",
39				"type:crypto/tls.clientHandshakeState",
40				"type:crypto/tls.serverHandshakeState",
41			},
42		},
43		{
44			name: "client_and_server",
45			program: `package main
46import "crypto/tls"
47func main() {
48  tls.Dial("", "", nil)
49  tls.Server(nil, nil)
50}
51`,
52			want: []string{
53				"crypto/tls.(*Conn).clientHandshake",
54				"crypto/tls.(*Conn).serverHandshake",
55			},
56		},
57		{
58			name: "only_client",
59			program: `package main
60import "crypto/tls"
61func main() { tls.Dial("", "", nil) }
62`,
63			want: []string{
64				"crypto/tls.(*Conn).clientHandshake",
65			},
66			bad: []string{
67				"crypto/tls.(*Conn).serverHandshake",
68			},
69		},
70		// TODO: add only_server like func main() { tls.Server(nil, nil) }
71		// That currently brings in the client via Conn.handleRenegotiation.
72
73	}
74	tmpDir := t.TempDir()
75	goFile := filepath.Join(tmpDir, "x.go")
76	exeFile := filepath.Join(tmpDir, "x.exe")
77	for _, tt := range tests {
78		t.Run(tt.name, func(t *testing.T) {
79			if err := os.WriteFile(goFile, []byte(tt.program), 0644); err != nil {
80				t.Fatal(err)
81			}
82			os.Remove(exeFile)
83			cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
84			cmd.Dir = tmpDir
85			if out, err := cmd.CombinedOutput(); err != nil {
86				t.Fatalf("compile: %v, %s", err, out)
87			}
88
89			cmd = exec.Command(goBin, "tool", "nm", "x.exe")
90			cmd.Dir = tmpDir
91			nm, err := cmd.CombinedOutput()
92			if err != nil {
93				t.Fatalf("nm: %v, %s", err, nm)
94			}
95			for _, sym := range tt.want {
96				if !bytes.Contains(nm, []byte(sym)) {
97					t.Errorf("expected symbol %q not found", sym)
98				}
99			}
100			for _, sym := range tt.bad {
101				if bytes.Contains(nm, []byte(sym)) {
102					t.Errorf("unexpected symbol %q found", sym)
103				}
104			}
105		})
106	}
107}
108