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 # Trimming file information for the UndefinedBehaviorSanitizer is permitted for internal linking.
60 env CGO_CFLAGS=-fsanitize-undefined-strip-path-components=-1
61 go build -x -n -o dummy.exe ./usesInternalCgo
62 ! stderr preferlinkext
63 env CGO_CFLAGS=-fsanitize-undefined-strip-path-components=2
64 go build -x -n -o dummy.exe ./usesInternalCgo
65 ! stderr preferlinkext
66
67 # The -fdebug-prefix-map=path is permitted for internal linking.
68 env CGO_CFLAGS=-fdebug-prefix-map=/some/sandbox/execroot/workspace=/tmp/new
69 go build -x -n -o dummy.exe ./usesInternalCgo
70 ! stderr preferlinkext
71 env CGO_CFLAGS=-fdebug-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static=.
72 go build -x -n -o dummy.exe ./usesInternalCgo
73 ! stderr preferlinkext
74 # The -ffile-prefix-map=path is permitted for internal linking too.
75 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_=.
76 go build -x -n -o dummy.exe ./usesInternalCgo
77 ! stderr preferlinkext
78 # Verifying that -fdebug-prefix-map=path, -ffile-prefix-map, -no-canonical-prefixes
79 # and -fno-canonical-systemd-headers are permitted for internal linking.
80 env CGO_CFLAGS=-fdebug-prefix-map=old=/tmp/new
81 go build -x -n -o dummy.exe ./usesInternalCgo
82 ! stderr preferlinkext
83 env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/_11233/things=new
84 go build -x -n -o dummy.exe ./usesInternalCgo
85 ! stderr preferlinkext
86 env CGO_CFLAGS=-no-canonical-prefixes
87 go build -x -n -o dummy.exe ./usesInternalCgo
88 ! stderr preferlinkext
89 env CGO_CFLAGS=-fno-canonical-system-headers
90 go build -x -n -o dummy.exe ./usesInternalCgo
91 ! stderr preferlinkext
92 env CGO_CFLAGS=
93
94 # CGO_LDFLAGS with -static variants are not compatible with internal linking.
95 env CGO_LDFLAGS=-static
96 go build -x -n -o dummy.exe ./usesInternalCgo
97 stderr preferlinkext
98 env CGO_LDFLAGS=--static
99 go build -x -n -o dummy.exe ./usesInternalCgo
100 stderr preferlinkext
101 env CGO_LDFLAGS=-Wl,-static
102 go build -x -n -o dummy.exe ./usesInternalCgo
103 stderr preferlinkext
104 env CGO_LDFLAGS=-Wl,--static
105 go build -x -n -o dummy.exe ./usesInternalCgo
106 stderr preferlinkext
107 env CGO_LDFLAGS=-Wl,-Bstatic
108 go build -x -n -o dummy.exe ./usesInternalCgo
109 stderr preferlinkext
110 env CGO_LDFLAGS=
111
112 # CGO_LDFLAGS=-static-libgcc does NOT trigger external linking.
113 env CGO_LDFLAGS=-static-libgcc
114 go build -x -n -o dummy.exe ./usesInternalCgo
115 ! stderr preferlinkext
116 env CGO_LDFLAGS=
117
118 # CGO_CFLAGS=--static triggers external linking (some toolchains accept it).
119 env CGO_CFLAGS=--static
120 go build -x -n -o dummy.exe ./usesInternalCgo
121 stderr preferlinkext
122 env CGO_CFLAGS=
123
124 [short] skip
125
126 # In the remaining tests below we do actual builds (without -n) to
127 # verify that the Go linker is going the right thing in addition to the
128 # Go command. Here the idea is to pass "-tmpdir" to the linker, then
129 # check after the link is done for the presence of the file
130 # <tmpdir>/go.o, which the Go linker creates prior to kicking off the
131 # external linker.
132
133 mkdir tmp1
134 mkdir tmp2
135 mkdir tmp3
136 mkdir tmp4
137 mkdir tmp5
138
139 # First build: no external linking expected
140 go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
141
142 # Second build: using only "runtime/cgo", expect internal linking.
143 go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo &
144
145 # Third build: program uses only "runtime/cgo", so we would normally
146 # expect internal linking, except that cflags contain suspicious entries
147 # (in this case, a flag that does not appear on the allow list).
148 env CGO_CFLAGS=-fmerge-all-constants
149 env CGO_LDFLAGS=-fmerge-all-constants
150 go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
151 env CGO_CFLAGS=
152 env CGO_LDFLAGS=
153
154 # Fourth build: explicit CGO, expect external linking.
155 go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo &
156
157 # Fifth build: explicit CGO, but we specifically asked for internal linking
158 # via a flag, so using internal linking it is.
159 [cgolinkext] go list ./usesInternalCgo
160 [!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo &
161
162 # Sixth build: explicit CGO use in a non-main package.
163 go build -o p.a ./nonMainPackageUsesExplicitCgo &
164
165 wait
166
167 # Check first build: no external linking expected
168 ! exists tmp1/go.o
169
170 # Check second build: using only "runtime/cgo", expect internal linking.
171 [!cgolinkext] ! exists tmp2/go.o
172 [cgolinkext] exists tmp2/go.o
173
174 # Check third build: has suspicious flag.
175 exists tmp3/go.o
176
177 # Fourth build: explicit CGO, expect external linking.
178 exists tmp4/go.o
179
180 # Fifth build: explicit CGO, -linkmode=internal.
181 ! exists tmp5/go.o
182
183 # Sixth build: make sure that "go tool nm" doesn't get confused
184 # by the presence of the "preferlinkext" sentinel.
185 go tool nm p.a
186
187 -- go.mod --
188
189 module cgo.example
190
191 go 1.20
192
193 -- noUseOfCgo/main.go --
194
195 package main
196
197 func main() {
198 println("clean as a whistle")
199 }
200
201 -- usesInternalCgo/main.go --
202
203 package main
204
205 import (
206 "runtime/cgo"
207 )
208
209 func main() {
210 q := "hello"
211 h := cgo.NewHandle(q)
212 h.Delete()
213 }
214
215 -- usesExplicitCgo/main.go --
216
217 package main
218
219 /*
220 int meaningOfLife() { return 42; }
221 */
222 import "C"
223
224 func main() {
225 println(C.meaningOfLife())
226 }
227
228 -- nonMainPackageUsesExplicitCgo/main.go --
229
230 package p
231
232 /*
233 int meaningOfLife() { return 42; }
234 */
235 import "C"
236
237 func PrintIt() {
238 println(C.meaningOfLife())
239 }
240
View as plain text