...
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.
33env GOCACHE=$WORK/gocache
34mkdir $GOCACHE
35
36# First build: there is no CGO in use, so no token should be present regardless
37# of weird CGO flags.
38go build -x -n -o dummy.exe ./noUseOfCgo
39! stderr preferlinkext
40env CGO_CFLAGS=-flto
41go build -x -n -o dummy.exe ./noUseOfCgo
42! stderr preferlinkext
43env 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.
47go build -x -n -o dummy.exe ./usesInternalCgo
48! stderr preferlinkext
49env CGO_CFLAGS=-flto
50go build -x -n -o dummy.exe ./usesInternalCgo
51stderr preferlinkext
52env CGO_CFLAGS=-fplugin
53go build -x -n -o dummy.exe ./usesInternalCgo
54stderr preferlinkext
55env CGO_CFLAGS=-fprofile-instr-generate
56go build -x -n -o dummy.exe ./usesInternalCgo
57stderr preferlinkext
58
59# Trimming file information for the UndefinedBehaviorSanitizer is permitted for internal linking.
60env CGO_CFLAGS=-fsanitize-undefined-strip-path-components=-1
61go build -x -n -o dummy.exe ./usesInternalCgo
62! stderr preferlinkext
63env CGO_CFLAGS=-fsanitize-undefined-strip-path-components=2
64go build -x -n -o dummy.exe ./usesInternalCgo
65! stderr preferlinkext
66
67# The -fdebug-prefix-map=path is permitted for internal linking.
68env CGO_CFLAGS=-fdebug-prefix-map=/some/sandbox/execroot/workspace=/tmp/new
69go build -x -n -o dummy.exe ./usesInternalCgo
70! stderr preferlinkext
71env CGO_CFLAGS=-fdebug-prefix-map=/Users/someone/.cache/bazel/_bazel_someone/3fa7e4650c43657ead684537951f49e2/sandbox/linux-sandbox/10/execroot/rules_go_static=.
72go build -x -n -o dummy.exe ./usesInternalCgo
73! stderr preferlinkext
74# The -ffile-prefix-map=path is permitted for internal linking too.
75env 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_=.
76go 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.
80env CGO_CFLAGS=-fdebug-prefix-map=old=/tmp/new
81go build -x -n -o dummy.exe ./usesInternalCgo
82! stderr preferlinkext
83env CGO_CFLAGS=-ffile-prefix-map=/Users/someone/_11233/things=new
84go build -x -n -o dummy.exe ./usesInternalCgo
85! stderr preferlinkext
86env CGO_CFLAGS=-no-canonical-prefixes
87go build -x -n -o dummy.exe ./usesInternalCgo
88! stderr preferlinkext
89env CGO_CFLAGS=-fno-canonical-system-headers
90go build -x -n -o dummy.exe ./usesInternalCgo
91! stderr preferlinkext
92env 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
103mkdir tmp1
104mkdir tmp2
105mkdir tmp3
106mkdir tmp4
107mkdir tmp5
108
109# First build: no external linking expected
110go build -ldflags=-tmpdir=tmp1 -o $devnull ./noUseOfCgo &
111
112# Second build: using only "runtime/cgo", expect internal linking.
113go 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).
118env CGO_CFLAGS=-fmerge-all-constants
119env CGO_LDFLAGS=-fmerge-all-constants
120go build -ldflags=-tmpdir=tmp3 -o $devnull ./usesInternalCgo &
121env CGO_CFLAGS=
122env CGO_LDFLAGS=
123
124# Fourth build: explicit CGO, expect external linking.
125go 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.
133go build -o p.a ./nonMainPackageUsesExplicitCgo &
134
135wait
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.
145exists tmp3/go.o
146
147# Fourth build: explicit CGO, expect external linking.
148exists 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.
155go tool nm p.a
156
157-- go.mod --
158
159module cgo.example
160
161go 1.20
162
163-- noUseOfCgo/main.go --
164
165package main
166
167func main() {
168 println("clean as a whistle")
169}
170
171-- usesInternalCgo/main.go --
172
173package main
174
175import (
176 "runtime/cgo"
177)
178
179func main() {
180 q := "hello"
181 h := cgo.NewHandle(q)
182 h.Delete()
183}
184
185-- usesExplicitCgo/main.go --
186
187package main
188
189/*
190int meaningOfLife() { return 42; }
191*/
192import "C"
193
194func main() {
195 println(C.meaningOfLife())
196}
197
198-- nonMainPackageUsesExplicitCgo/main.go --
199
200package p
201
202/*
203int meaningOfLife() { return 42; }
204*/
205import "C"
206
207func PrintIt() {
208 println(C.meaningOfLife())
209}
View as plain text