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 [short] skip
95
96 # In the remaining tests below we do actual builds (without -n) to
97 # verify that the Go linker is going the right thing in addition to the
98 # Go command. Here the idea is to pass "-tmpdir" to the linker, then
99 # check after the link is done for the presence of the file
100 # <tmpdir>/go.o, which the Go linker creates prior to kicking off the
101 # external linker.
102
103 mkdir tmp1
104 mkdir tmp2
105 mkdir tmp3
106 mkdir tmp4
107 mkdir tmp5
108
109 # First build: no external linking expected
110 go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
111
112 # Second build: using only "runtime/cgo", expect internal linking.
113 go build -ldflags=-tmpdir=tmp2 -o $devnull ./usesInternalCgo &
114
115 # Third build: program uses only "runtime/cgo", so we would normally
116 # expect internal linking, except that cflags contain suspicious entries
117 # (in this case, a flag that does not appear on the allow list).
118 env CGO_CFLAGS=-fmerge-all-constants
119 env CGO_LDFLAGS=-fmerge-all-constants
120 go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
121 env CGO_CFLAGS=
122 env CGO_LDFLAGS=
123
124 # Fourth build: explicit CGO, expect external linking.
125 go build -ldflags=-tmpdir=tmp4 -o $devnull ./usesExplicitCgo &
126
127 # Fifth build: explicit CGO, but we specifically asked for internal linking
128 # via a flag, so using internal linking it is.
129 [cgolinkext] go list ./usesInternalCgo
130 [!cgolinkext] go build '-ldflags=-tmpdir=tmp5 -linkmode=internal' -o $devnull ./usesInternalCgo &
131
132 # Sixth build: explicit CGO use in a non-main package.
133 go build -o p.a ./nonMainPackageUsesExplicitCgo &
134
135 wait
136
137 # Check first build: no external linking expected
138 ! exists tmp1/go.o
139
140 # Check second build: using only "runtime/cgo", expect internal linking.
141 [!cgolinkext] ! exists tmp2/go.o
142 [cgolinkext] exists tmp2/go.o
143
144 # Check third build: has suspicious flag.
145 exists tmp3/go.o
146
147 # Fourth build: explicit CGO, expect external linking.
148 exists tmp4/go.o
149
150 # Fifth build: explicit CGO, -linkmode=internal.
151 ! exists tmp5/go.o
152
153 # Sixth build: make sure that "go tool nm" doesn't get confused
154 # by the presence of the "preferlinkext" sentinel.
155 go tool nm p.a
156
157 -- go.mod --
158
159 module cgo.example
160
161 go 1.20
162
163 -- noUseOfCgo/main.go --
164
165 package main
166
167 func main() {
168 println("clean as a whistle")
169 }
170
171 -- usesInternalCgo/main.go --
172
173 package main
174
175 import (
176 "runtime/cgo"
177 )
178
179 func main() {
180 q := "hello"
181 h := cgo.NewHandle(q)
182 h.Delete()
183 }
184
185 -- usesExplicitCgo/main.go --
186
187 package main
188
189 /*
190 int meaningOfLife() { return 42; }
191 */
192 import "C"
193
194 func main() {
195 println(C.meaningOfLife())
196 }
197
198 -- nonMainPackageUsesExplicitCgo/main.go --
199
200 package p
201
202 /*
203 int meaningOfLife() { return 42; }
204 */
205 import "C"
206
207 func PrintIt() {
208 println(C.meaningOfLife())
209 }
210
View as plain text