link_test.go 2.4 KB

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