• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pantsbuild / pants / 18517631058

15 Oct 2025 04:18AM UTC coverage: 69.207% (-11.1%) from 80.267%
18517631058

Pull #22745

github

web-flow
Merge 642a76ca1 into 99919310e
Pull Request #22745: [windows] Add windows support in the stdio crate.

53815 of 77759 relevant lines covered (69.21%)

2.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

29.31
/src/python/pants/backend/go/util_rules/cgo_security.py
1
# Copyright 2022 Pants project contributors (see CONTRIBUTORS.md).
2
# Licensed under the Apache License, Version 2.0 (see LICENSE).
3
from __future__ import annotations
7✔
4

5
import re
7✔
6
import string
7✔
7
from collections.abc import Iterable, Sequence
7✔
8

9
from pants.util.memo import memoized
7✔
10

11
#
12
# Check compiler and linker arguments in CGo use cases against explicit allow lists.
13
# Adapted from https://github.com/golang/go/blob/master/src/cmd/go/internal/work/security.go.
14
#
15
# Original copyright:
16
#   // Copyright 2018 The Go Authors. All rights reserved.
17
#   // Use of this source code is governed by a BSD-style
18
#   // license that can be found in the LICENSE file.
19

20

21
class CGoFlagSecurityError(ValueError):
7✔
22
    pass
7✔
23

24

25
@memoized
7✔
26
def _valid_compiler_flags() -> tuple[re.Pattern, ...]:
7✔
27
    return (
×
28
        re.compile(r"-D([A-Za-z_][A-Za-z0-9_]*)(=[^@\-]*)?"),
29
        re.compile(r"-U([A-Za-z_][A-Za-z0-9_]*)"),
30
        re.compile(r"-F([^@\-].*)"),
31
        re.compile(r"-I([^@\-].*)"),
32
        re.compile(r"-O"),
33
        re.compile(r"-O([^@\-].*)"),
34
        re.compile(r"-W"),
35
        re.compile(r"-W([^@,]+)"),  # -Wall but not -Wa,-foo.
36
        re.compile(r"-Wa,-mbig-obj"),
37
        re.compile(r"-Wp,-D([A-Za-z_][A-Za-z0-9_]*)(=[^@,\-]*)?"),
38
        re.compile(r"-Wp,-U([A-Za-z_][A-Za-z0-9_]*)"),
39
        re.compile(r"-ansi"),
40
        re.compile(r"-f(no-)?asynchronous-unwind-tables"),
41
        re.compile(r"-f(no-)?blocks"),
42
        re.compile(r"-f(no-)builtin-[a-zA-Z0-9_]*"),
43
        re.compile(r"-f(no-)?common"),
44
        re.compile(r"-f(no-)?constant-cfstrings"),
45
        re.compile(r"-fdiagnostics-show-note-include-stack"),
46
        re.compile(r"-f(no-)?eliminate-unused-debug-types"),
47
        re.compile(r"-f(no-)?exceptions"),
48
        re.compile(r"-f(no-)?fast-math"),
49
        re.compile(r"-f(no-)?inline-functions"),
50
        re.compile(r"-finput-charset=([^@\-].*)"),
51
        re.compile(r"-f(no-)?fat-lto-objects"),
52
        re.compile(r"-f(no-)?keep-inline-dllexport"),
53
        re.compile(r"-f(no-)?lto"),
54
        re.compile(r"-fmacro-backtrace-limit=(.+)"),
55
        re.compile(r"-fmessage-length=(.+)"),
56
        re.compile(r"-f(no-)?modules"),
57
        re.compile(r"-f(no-)?objc-arc"),
58
        re.compile(r"-f(no-)?objc-nonfragile-abi"),
59
        re.compile(r"-f(no-)?objc-legacy-dispatch"),
60
        re.compile(r"-f(no-)?omit-frame-pointer"),
61
        re.compile(r"-f(no-)?openmp(-simd)?"),
62
        re.compile(r"-f(no-)?permissive"),
63
        re.compile(r"-f(no-)?(pic|PIC|pie|PIE)"),
64
        re.compile(r"-f(no-)?plt"),
65
        re.compile(r"-f(no-)?rtti"),
66
        re.compile(r"-f(no-)?split-stack"),
67
        re.compile(r"-f(no-)?stack-(.+)"),
68
        re.compile(r"-f(no-)?strict-aliasing"),
69
        re.compile(r"-f(un)signed-char"),
70
        re.compile(r"-f(no-)?use-linker-plugin"),  # safe if -B is not used; we don't permit -B
71
        re.compile(r"-f(no-)?visibility-inlines-hidden"),
72
        re.compile(r"-fsanitize=(.+)"),
73
        re.compile(r"-ftemplate-depth-(.+)"),
74
        re.compile(r"-fvisibility=(.+)"),
75
        re.compile(r"-g([^@\-].*)?"),
76
        re.compile(r"-m32"),
77
        re.compile(r"-m64"),
78
        re.compile(r"-m(abi|arch|cpu|fpu|tune)=([^@\-].*)"),
79
        re.compile(r"-m(no-)?v?aes"),
80
        re.compile(r"-marm"),
81
        re.compile(r"-m(no-)?avx[0-9a-z]*"),
82
        re.compile(r"-mfloat-abi=([^@\-].*)"),
83
        re.compile(r"-mfpmath=[0-9a-z,+]*"),
84
        re.compile(r"-m(no-)?avx[0-9a-z.]*"),
85
        re.compile(r"-m(no-)?ms-bitfields"),
86
        re.compile(r"-m(no-)?stack-(.+)"),
87
        re.compile(r"-mmacosx-(.+)"),
88
        re.compile(r"-mios-simulator-version-min=(.+)"),
89
        re.compile(r"-miphoneos-version-min=(.+)"),
90
        re.compile(r"-mtvos-simulator-version-min=(.+)"),
91
        re.compile(r"-mtvos-version-min=(.+)"),
92
        re.compile(r"-mwatchos-simulator-version-min=(.+)"),
93
        re.compile(r"-mwatchos-version-min=(.+)"),
94
        re.compile(r"-mnop-fun-dllimport"),
95
        re.compile(r"-m(no-)?sse[0-9.]*"),
96
        re.compile(r"-m(no-)?ssse3"),
97
        re.compile(r"-mthumb(-interwork)?"),
98
        re.compile(r"-mthreads"),
99
        re.compile(r"-mwindows"),
100
        re.compile(r"--param=ssp-buffer-size=[0-9]*"),
101
        re.compile(r"-pedantic(-errors)?"),
102
        re.compile(r"-pipe"),
103
        re.compile(r"-pthread"),
104
        re.compile(r"-?-std=([^@\-].*)"),
105
        re.compile(r"-?-stdlib=([^@\-].*)"),
106
        re.compile(r"--sysroot=([^@\-].*)"),
107
        re.compile(r"-w"),
108
        re.compile(r"-x([^@\-].*)"),
109
        re.compile(r"-v"),
110
    )
111

112

113
_valid_compiler_flags_with_next_arg = (
7✔
114
    "-arch",
115
    "-D",
116
    "-U",
117
    "-I",
118
    "-F",
119
    "-framework",
120
    "-include",
121
    "-isysroot",
122
    "-isystem",
123
    "--sysroot",
124
    "-target",
125
    "-x",
126
)
127

128

129
@memoized
7✔
130
def _valid_linker_flags() -> tuple[re.Pattern, ...]:
7✔
131
    return (
×
132
        re.compile(r"-F([^@\-].*)"),
133
        re.compile(r"-l([^@\-].*)"),
134
        re.compile(r"-L([^@\-].*)"),
135
        re.compile(r"-O"),
136
        re.compile(r"-O([^@\-].*)"),
137
        re.compile(r"-f(no-)?(pic|PIC|pie|PIE)"),
138
        re.compile(r"-f(no-)?openmp(-simd)?"),
139
        re.compile(r"-fsanitize=([^@\-].*)"),
140
        re.compile(r"-flat_namespace"),
141
        re.compile(r"-g([^@\-].*)?"),
142
        re.compile(r"-headerpad_max_install_names"),
143
        re.compile(r"-m(abi|arch|cpu|fpu|tune)=([^@\-].*)"),
144
        re.compile(r"-mfloat-abi=([^@\-].*)"),
145
        re.compile(r"-mmacosx-(.+)"),
146
        re.compile(r"-mios-simulator-version-min=(.+)"),
147
        re.compile(r"-miphoneos-version-min=(.+)"),
148
        re.compile(r"-mthreads"),
149
        re.compile(r"-mwindows"),
150
        re.compile(r"-(pic|PIC|pie|PIE)"),
151
        re.compile(r"-pthread"),
152
        re.compile(r"-rdynamic"),
153
        re.compile(r"-shared"),
154
        re.compile(r"-?-static([-a-z0-9+]*)"),
155
        re.compile(r"-?-stdlib=([^@\-].*)"),
156
        re.compile(r"-v"),
157
        # Note that any wildcards in -Wl need to exclude comma,
158
        # since -Wl splits its argument at commas and passes
159
        # them all to the linker uninterpreted. Allowing comma
160
        # in a wildcard would allow tunneling arbitrary additional
161
        # linker arguments through one of these.
162
        re.compile(r"-Wl,--(no-)?allow-multiple-definition"),
163
        re.compile(r"-Wl,--(no-)?allow-shlib-undefined"),
164
        re.compile(r"-Wl,--(no-)?as-needed"),
165
        re.compile(r"-Wl,-Bdynamic"),
166
        re.compile(r"-Wl,-berok"),
167
        re.compile(r"-Wl,-Bstatic"),
168
        re.compile(r"-Wl,-Bsymbolic-functions"),
169
        re.compile(r"-Wl,-O([^@,\-][^,]*)?"),
170
        re.compile(r"-Wl,-d[ny]"),
171
        re.compile(r"-Wl,--disable-new-dtags"),
172
        re.compile(r"-Wl,-e[=,][a-zA-Z0-9]*"),
173
        re.compile(r"-Wl,--enable-new-dtags"),
174
        re.compile(r"-Wl,--end-group"),
175
        re.compile(r"-Wl,--(no-)?export-dynamic"),
176
        re.compile(r"-Wl,-E"),
177
        re.compile(r"-Wl,-framework,[^,@\-][^,]+"),
178
        re.compile(r"-Wl,--hash-style=(sysv|gnu|both)"),
179
        re.compile(r"-Wl,-headerpad_max_install_names"),
180
        re.compile(r"-Wl,--no-undefined"),
181
        re.compile(r"-Wl,-R([^@\-][^,@]*$)"),
182
        re.compile(r"-Wl,--just-symbols[=,]([^,@\-][^,@]+)"),
183
        re.compile(r"-Wl,-rpath(-link)?[=,]([^,@\-][^,]+)"),
184
        re.compile(r"-Wl,-s"),
185
        re.compile(r"-Wl,-search_paths_first"),
186
        re.compile(r"-Wl,-sectcreate,([^,@\-][^,]+),([^,@\-][^,]+),([^,@\-][^,]+)"),
187
        re.compile(r"-Wl,--start-group"),
188
        re.compile(r"-Wl,-?-static"),
189
        re.compile(r"-Wl,-?-subsystem,(native|windows|console|posix|xbox)"),
190
        re.compile(r"-Wl,-syslibroot[=,]([^,@\-][^,]+)"),
191
        re.compile(r"-Wl,-undefined[=,]([^,@\-][^,]+)"),
192
        re.compile(r"-Wl,-?-unresolved-symbols=[^,]+"),
193
        re.compile(r"-Wl,--(no-)?warn-([^,]+)"),
194
        re.compile(r"-Wl,-?-wrap[=,][^,@\-][^,]*"),
195
        re.compile(r"-Wl,-z,(no)?execstack"),
196
        re.compile(r"-Wl,-z,relro"),
197
        re.compile(
198
            r"[a-zA-Z0-9_/].*\.(a|o|obj|dll|dylib|so|tbd)"
199
        ),  # direct linker inputs: x.o or libfoo.so (but not -foo.o or @foo.o)
200
        re.compile(r"\./.*\.(a|o|obj|dll|dylib|so|tbd)"),
201
    )
202

203

204
_valid_linker_flags_with_next_arg = (
7✔
205
    "-arch",
206
    "-F",
207
    "-l",
208
    "-L",
209
    "-framework",
210
    "-isysroot",
211
    "--sysroot",
212
    "-target",
213
    "-Wl,-framework",
214
    "-Wl,-rpath",
215
    "-Wl,-R",
216
    "-Wl,--just-symbols",
217
    "-Wl,-undefined",
218
)
219

220

221
# SafeArg reports whether arg is a "safe" command-line argument,
222
# meaning that when it appears in a command-line, it probably
223
# doesn't have some special meaning other than its own name.
224
# Obviously args beginning with - are not safe (they look like flags).
225
# Less obviously, args beginning with @ are not safe (they look like
226
# GNU binutils flagfile specifiers, sometimes called "response files").
227
# To be conservative, we reject almost any arg beginning with non-alphanumeric ASCII.
228
# We accept leading . _ and / as likely in file system paths.
229
# There is a copy of this function in cmd/compile/internal/gc/noder.go.
230
def safe_arg(name: str) -> bool:
7✔
231
    if name == "":
×
232
        return False
×
233
    c = name[0]
×
234
    return (
×
235
        c in string.digits
236
        or c in string.ascii_letters
237
        or c == "."
238
        or c == "_"
239
        or c == "/"
240
        or ord(c) >= 0x80
241
    )
242

243

244
def _check_flags(
7✔
245
    flags: Sequence[str],
246
    regexps: Iterable[re.Pattern],
247
    valid_next_options: Iterable[str],
248
    source: str,
249
):
250
    i = 0
×
251
    while i < len(flags):
×
252
        flag = flags[i]
×
253
        continue_outer_loop = False
×
254
        for regexp in regexps:
×
255
            m = regexp.fullmatch(flag)
×
256
            if m:
×
257
                i = i + 1
×
258
                continue_outer_loop = True
×
259
                break
×
260

261
        if continue_outer_loop:
×
262
            continue
×
263

264
        for valid_next_option in valid_next_options:
×
265
            if valid_next_option == flag:
×
266
                if i + 1 < len(flags) and safe_arg(flags[i + 1]):
×
267
                    i = i + 2
×
268
                    continue_outer_loop = True
×
269
                    break
×
270

271
                # Permit -Wl,-framework -Wl,name.
272
                if (
×
273
                    i + 1 < len(flags)
274
                    and flag.startswith("-Wl,")
275
                    and flags[i + 1].startswith("-Wl,")
276
                    and safe_arg(flags[i + 1][4:])
277
                    and "," not in flags[i + 1][4:]
278
                ):
279
                    i = i + 2
×
280
                    continue_outer_loop = True
×
281
                    break
×
282

283
                # Permit -I= /path, -I $SYSROOT.
284
                if i + 1 < len(flags) and flag == "-I":
×
285
                    if (
×
286
                        flags[i + 1].startswith("=") or flags[i + 1].startswith("$SYSROOT")
287
                    ) and safe_arg(flags[i + 1][1:]):
288
                        i = i + 2
×
289
                        continue_outer_loop = True
×
290
                        break
×
291

292
                if i + 1 < len(flags):
×
293
                    raise CGoFlagSecurityError(
×
294
                        f"invalid flag in {source}: {flag} {flags[i + 1]} (see https://golang.org/s/invalidflag)"
295
                    )
296

297
                raise CGoFlagSecurityError(
×
298
                    f"invalid flag in {source}: {flag} without argument (see https://golang.org/s/invalidflag)"
299
                )
300

301
        if continue_outer_loop:
×
302
            continue
×
303

304
        raise CGoFlagSecurityError(f"invalid flag in {source}: {flag}")
×
305

306

307
def check_compiler_flags(flags: Sequence[str], source: str):
7✔
308
    _check_flags(flags, _valid_compiler_flags(), _valid_compiler_flags_with_next_arg, source)
×
309

310

311
def check_linker_flags(flags: Sequence[str], source: str):
7✔
312
    _check_flags(flags, _valid_linker_flags(), _valid_linker_flags_with_next_arg, source)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc