Text file
src/cmd/go/testdata/script/cgo_suspect_flag_force_external.txt
1 # Test case to verify that when we have a package that uses CGO in
2 # combination with selected "unusual" flags (involving plugins, LTO)
3 # that we force external linking. See related
4 # issues 58619, 58620, and 58848.
5
6 [compiler:gccgo] skip # only external linking for gccgo
7
8 [!cgo] skip 'test verifies behavior that depends on CGO_CFLAGS'
9 [mustlinkext] skip 'test expects internal linking for non-cgo programs'
10
11 # Here we build three program: one with explicit CGO use, one with no
12 # CGO use, and one that uses a stdlib package ("runtime/cgo") that has
13 # CGO in it. It used to be that only the explicit use of CGO would
14 # trigger external linking, and that the program that only used
15 # "runtime/cgo" would always be handled with internal linking. This caused
16 # issues when users included odd/unusual flags (ex: -fplugin, -flto)
17 # in CGO_CFLAGS, causing the Go linker to have to read and interpret
18 # non-standard host objects.
19 #
20 # As of 1.21 we continue to use internal linking for programs whose
21 # CGO use comes only from stdlib packages in the absence of any flag
22 # funny business, however if the Go command sees flags that may be suspicious,
23 # it signals the Go linker to invoke the external linker.
24
25 # The next few tests run builds passing "-n" to the Go command, then
26 # checking the output to see if the Go command is trying to pass a
27 # "preferlinkext" token to the linker to request external linking.
28
29 #-----------------------
30
31 # Use a fresh GOCACHE for these next steps, so as to have the real
32 # actions for the runtime/cgo package appear in the "-n -x" output.
33 env GOCACHE=$WORK/gocache
34 mkdir $GOCACHE
35
36 # First build: there is no CGO in use, so no token should be present regardless
37 # of weird CGO flags.
38 go build -x -n -o dummy.exe ./noUseOfCgo
39 ! stderr preferlinkext
40 env CGO_CFLAGS=-flto
41 go build -x -n -o dummy.exe ./noUseOfCgo
42 ! stderr preferlinkext
43 env CGO_CFLAGS=
44
45 # Second build uses CGO, so we expect to see the token present in the
46 # -n output only when strange flags are used.
47 go build -x -n -o dummy.exe ./usesInternalCgo
48 ! stderr preferlinkext
49 env CGO_CFLAGS=-flto
50 go build -x -n -o dummy.exe ./usesInternalCgo
51 stderr preferlinkext
52 env CGO_CFLAGS=-fplugin
53 go build -x -n -o dummy.exe ./usesInternalCgo
54 stderr preferlinkext
55 env CGO_CFLAGS=-fprofile-instr-generate
56 go build -x -n -o dummy.exe ./usesInternalCgo
57 stderr preferlinkext
58
59 # The -fdebug-prefix-map=path is permitted for internal linking.
60 env CGO_CFLAGS=-fdebug-prefix-map=/some/sandbox/execroot/workspace=/tmp/new
61 go build -x -n -o dummy.exe ./usesInternalCgo
62 ! stderr preferlinkext
63 env CGO_CFLAGS=-fdebug-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static=.
64 go build -x -n -o dummy.exe ./usesInternalCgo
65 ! stderr preferlinkext
66 # The -ffile-prefix-map=path is permitted for internal linking too.
67 env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static/bazel-out/aarch64-fastbuild-ST-b33d65c724e6/bin/external/io_bazel_rules_go/stdlib_=.
68 go build -x -n -o dummy.exe ./usesInternalCgo
69 ! stderr preferlinkext
70 # Verifying that -fdebug-prefix-map=path, -ffile-prefix-map, -no-canonical-prefixes
71 # and -fno-canonical-systemd-headers are permitted for internal linking.
72 env CGO_CFLAGS=-fdebug-prefix-map=old=/tmp/new
73 go build -x -n -o dummy.exe ./usesInternalCgo
74 ! stderr preferlinkext
75 env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/_11233/things=new
76 go build -x -n -o dummy.exe ./usesInternalCgo
77 ! stderr preferlinkext
78 env CGO_CFLAGS=-no-canonical-prefixes
79 go build -x -n -o dummy.exe ./usesInternalCgo
80 ! stderr preferlinkext
81 env CGO_CFLAGS=-fno-canonical-system-headers
82 go build -x -n -o dummy.exe ./usesInternalCgo
83 ! stderr preferlinkext
84 env CGO_CFLAGS=
85
86 [short] skip
87
88 # In the remaining tests below we do actual builds (without -n) to
89 # verify that the Go linker is going the right thing in addition to the
90 # Go command. Here the idea is to pass "-tmpdir" to the linker, then
91 # check after the link is done for the presence of the file
92 # <tmpdir>/go.o, which the Go linker creates prior to kicking off the
93 # external linker.
94
95 mkdir tmp1
96 mkdir tmp2
97 mkdir tmp3
98 mkdir tmp4
99 mkdir tmp5
100
101 # First build: no external linking expected
102 go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
103
104 # Second build: using only "runtime/cgo", expect internal linking.
105 go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo &
106
107 # Third build: program uses only "runtime/cgo", so we would normally
108 # expect internal linking, except that cflags contain suspicious entries
109 # (in this case, a flag that does not appear on the allow list).
110 env CGO_CFLAGS=-fmerge-all-constants
111 env CGO_LDFLAGS=-fmerge-all-constants
112 go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
113 env CGO_CFLAGS=
114 env CGO_LDFLAGS=
115
116 # Fourth build: explicit CGO, expect external linking.
117 go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo &
118
119 # Fifth build: explicit CGO, but we specifically asked for internal linking
120 # via a flag, so using internal linking it is.
121 [cgolinkext] go list ./usesInternalCgo
122 [!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo &
123
124 # Sixth build: explicit CGO use in a non-main package.
125 go build -o p.a ./nonMainPackageUsesExplicitCgo &
126
127 wait
128
129 # Check first build: no external linking expected
130 ! exists tmp1/go.o
131
132 # Check second build: using only "runtime/cgo", expect internal linking.
133 [!cgolinkext] ! exists tmp2/go.o
134 [cgolinkext] exists tmp2/go.o
135
136 # Check third build: has suspicious flag.
137 exists tmp3/go.o
138
139 # Fourth build: explicit CGO, expect external linking.
140 exists tmp4/go.o
141
142 # Fifth build: explicit CGO, -linkmode=internal.
143 ! exists tmp5/go.o
144
145 # Sixth build: make sure that "go tool nm" doesn't get confused
146 # by the presence of the "preferlinkext" sentinel.
147 go tool nm p.a
148
149 -- go.mod --
150
151 module cgo.example
152
153 go 1.20
154
155 -- noUseOfCgo/main.go --
156
157 package main
158
159 func main() {
160 println("clean as a whistle")
161 }
162
163 -- usesInternalCgo/main.go --
164
165 package main
166
167 import (
168 "runtime/cgo"
169 )
170
171 func main() {
172 q := "hello"
173 h := cgo.NewHandle(q)
174 h.Delete()
175 }
176
177 -- usesExplicitCgo/main.go --
178
179 package main
180
181 /*
182 int meaningOfLife() { return 42; }
183 */
184 import "C"
185
186 func main() {
187 println(C.meaningOfLife())
188 }
189
190 -- nonMainPackageUsesExplicitCgo/main.go --
191
192 package p
193
194 /*
195 int meaningOfLife() { return 42; }
196 */
197 import "C"
198
199 func PrintIt() {
200 println(C.meaningOfLife())
201 }
202
View as plain text