Skip to content

Commit 2623d60

Browse files
committed
Run 'python3-libraries' fuzzer in CI using CIFuzz
1 parent cea2d24 commit 2623d60

3 files changed

Lines changed: 107 additions & 1 deletion

File tree

.github/workflows/build.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -676,6 +676,45 @@ jobs:
676676
sarif_file: cifuzz-sarif/results.sarif
677677
checkout_path: cifuzz-sarif
678678

679+
cifuzz-libraries:
680+
name: CIFuzz-libraries
681+
runs-on: ubuntu-latest
682+
timeout-minutes: 60
683+
needs: build-context
684+
if: needs.build-context.outputs.run-ci-fuzz-libraries == 'true'
685+
permissions:
686+
security-events: write
687+
strategy:
688+
fail-fast: false
689+
matrix:
690+
sanitizer: [address, undefined, memory]
691+
steps:
692+
- name: Build fuzzers (${{ matrix.sanitizer }})
693+
id: build
694+
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
695+
with:
696+
oss-fuzz-project-name: python3-libraries
697+
sanitizer: ${{ matrix.sanitizer }}
698+
- name: Run fuzzers (${{ matrix.sanitizer }})
699+
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
700+
with:
701+
fuzz-seconds: 600
702+
oss-fuzz-project-name: python3-libraries
703+
output-sarif: true
704+
sanitizer: ${{ matrix.sanitizer }}
705+
- name: Upload crash
706+
if: failure() && steps.build.outcome == 'success'
707+
uses: actions/upload-artifact@v4
708+
with:
709+
name: ${{ matrix.sanitizer }}-artifacts
710+
path: ./out/artifacts
711+
- name: Upload SARIF
712+
if: always() && steps.build.outcome == 'success'
713+
uses: github/codeql-action/upload-sarif@v3
714+
with:
715+
sarif_file: cifuzz-sarif/results.sarif
716+
checkout_path: cifuzz-sarif
717+
679718
all-required-green: # This job does nothing and is only used for the branch protection
680719
name: All required checks pass
681720
runs-on: ubuntu-latest
@@ -698,6 +737,7 @@ jobs:
698737
- build-san
699738
- cross-build-linux
700739
- cifuzz
740+
- cifuzz-libraries
701741
if: always()
702742

703743
steps:
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Run the 'python3-libraries' fuzzer using CIFuzz. Automatically detect when
2+
modules are changed.

Tools/build/compute-changes.py

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,57 @@
5050
MACOS_DIRS = frozenset({"Mac"})
5151
WASI_DIRS = frozenset({Path("Tools", "wasm")})
5252

53+
LIBRARY_FUZZER_PATHS = frozenset({
54+
# All C/CPP fuzzers.
55+
Path("configure"),
56+
# ast
57+
Path("Lib/ast.py"),
58+
Path("Python/ast.c"),
59+
# configparser
60+
Path("Lib/configparser.py"),
61+
# csv
62+
Path("Lib/csv.py"),
63+
Path("Modules/_csv.c"),
64+
# decode
65+
Path("Lib/encodings/"),
66+
Path("Modules/_codecsmodule.c"),
67+
Path("Modules/cjkcodecs/"),
68+
Path("Modules/unicodedata*"),
69+
# difflib
70+
Path("Lib/difflib.py"),
71+
# email
72+
Path("Lib/email/"),
73+
# html
74+
Path("Lib/html/"),
75+
Path("Lib/_markupbase.py"),
76+
# http.client
77+
Path("Lib/http/client.py"),
78+
# json
79+
Path("Lib/json/"),
80+
Path("Modules/_json.c"),
81+
# plist
82+
Path("Lib/plistlib.py"),
83+
# re
84+
Path("Lib/re/"),
85+
Path("Modules/_sre/"),
86+
# tarfile
87+
Path("Lib/tarfile.py"),
88+
# tomllib
89+
Path("Modules/tomllib/"),
90+
# xml
91+
Path("Lib/xml/"),
92+
Path("Lib/_markupbase.py"),
93+
Path("Modules/expat/"),
94+
# zipfile
95+
Path("Lib/zipfile/"),
96+
})
97+
5398

5499
@dataclass(kw_only=True, slots=True)
55100
class Outputs:
56101
run_android: bool = False
57102
run_ci_fuzz: bool = False
103+
run_ci_fuzz_libraries: bool = False
58104
run_docs: bool = False
59105
run_ios: bool = False
60106
run_macos: bool = False
@@ -94,6 +140,11 @@ def compute_changes() -> None:
94140
else:
95141
print("Branch too old for CIFuzz tests; or no C files were changed")
96142

143+
if outputs.run_ci_fuzz_libraries:
144+
print("Run CIFuzz tests for libraries")
145+
else:
146+
print("Branch too old for CIFuzz tests; or no library files were changed")
147+
97148
if outputs.run_docs:
98149
print("Build documentation")
99150

@@ -144,9 +195,18 @@ def get_file_platform(file: Path) -> str | None:
144195
return None
145196

146197

198+
def is_fuzzable_library_file(file: Path) -> bool:
199+
return any(
200+
(file.is_relative_to(needs_fuzz) and needs_fuzz.is_dir())
201+
or (file == needs_fuzz and file.is_file())
202+
for needs_fuzz in LIBRARY_FUZZER_PATHS
203+
)
204+
205+
147206
def process_changed_files(changed_files: Set[Path]) -> Outputs:
148207
run_tests = False
149208
run_ci_fuzz = False
209+
run_ci_fuzz_libraries = False
150210
run_docs = False
151211
run_windows_tests = False
152212
run_windows_msi = False
@@ -161,7 +221,7 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
161221

162222
if file.parent == GITHUB_WORKFLOWS_PATH:
163223
if file.name == "build.yml":
164-
run_tests = run_ci_fuzz = True
224+
run_tests = run_ci_fuzz = run_ci_fuzz_libraries = True
165225
has_platform_specific_change = False
166226
if file.name == "reusable-docs.yml":
167227
run_docs = True
@@ -196,6 +256,8 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
196256
("Modules", "_xxtestfuzz"),
197257
}:
198258
run_ci_fuzz = True
259+
if not run_ci_fuzz_libraries and is_fuzzable_library_file(file):
260+
run_ci_fuzz_libraries = True
199261

200262
# Check for changed documentation-related files
201263
if doc_file:
@@ -229,6 +291,7 @@ def process_changed_files(changed_files: Set[Path]) -> Outputs:
229291
return Outputs(
230292
run_android=run_android,
231293
run_ci_fuzz=run_ci_fuzz,
294+
run_ci_fuzz_libraries=run_ci_fuzz_libraries,
232295
run_docs=run_docs,
233296
run_ios=run_ios,
234297
run_macos=run_macos,
@@ -265,6 +328,7 @@ def write_github_output(outputs: Outputs) -> None:
265328
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as f:
266329
f.write(f"run-android={bool_lower(outputs.run_android)}\n")
267330
f.write(f"run-ci-fuzz={bool_lower(outputs.run_ci_fuzz)}\n")
331+
f.write(f"run-ci-fuzz-libraries={bool_lower(outputs.run_ci_fuzz_libraries)}\n")
268332
f.write(f"run-docs={bool_lower(outputs.run_docs)}\n")
269333
f.write(f"run-ios={bool_lower(outputs.run_ios)}\n")
270334
f.write(f"run-macos={bool_lower(outputs.run_macos)}\n")

0 commit comments

Comments
 (0)