Source file src/crypto/tls/link_test.go

     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  
     5  package tls
     6  
     7  import (
     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.
    17  func 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
    34  import _ "crypto/tls"
    35  func 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
    46  import "crypto/tls"
    47  func 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
    60  import "crypto/tls"
    61  func 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  

View as plain text