Skip to content

Commit 81c7137

Browse files
joseph-isaacs0ax1
authored andcommitted
feat[cuda]: fuzz CUDA on CI
Signed-off-by: Alexander Droste <alexander.droste@protonmail.com>
1 parent a66a58d commit 81c7137

File tree

25 files changed

+398
-81
lines changed

25 files changed

+398
-81
lines changed

.github/workflows/fuzz.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ jobs:
2121
uses: ./.github/workflows/run-fuzzer.yml
2222
with:
2323
fuzz_target: file_io
24+
family: "m8g.large"
25+
image: "ubuntu24-full-arm64"
2426
secrets:
2527
R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
2628
R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
@@ -69,6 +71,8 @@ jobs:
6971
uses: ./.github/workflows/run-fuzzer.yml
7072
with:
7173
fuzz_target: array_ops
74+
family: "m8g.large"
75+
image: "ubuntu24-full-arm64"
7276
secrets:
7377
R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
7478
R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
@@ -103,6 +107,45 @@ jobs:
103107
uses: ./.github/workflows/run-fuzzer.yml
104108
with:
105109
fuzz_target: compress_roundtrip
110+
family: "m8g.large"
111+
image: "ubuntu24-full-arm64"
106112
secrets:
107113
R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
108114
R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
115+
116+
# ============================================================================
117+
# GPU Compress Fuzzer (CUDA)
118+
# ============================================================================
119+
gpu_compress_fuzz:
120+
name: "GPU Compress Fuzz"
121+
uses: ./.github/workflows/run-fuzzer.yml
122+
with:
123+
fuzz_target: compress_gpu
124+
family: "g4dn"
125+
image: "ubuntu24-gpu-x64"
126+
extra_features: "cuda"
127+
secrets:
128+
R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
129+
R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
130+
131+
# report-gpu-compress-fuzz-failures:
132+
# name: "Report GPU Compress Fuzz Failures"
133+
# needs: gpu_compress_fuzz
134+
# if: always() && needs.gpu_compress_fuzz.outputs.crashes_found == 'true'
135+
# permissions:
136+
# issues: write
137+
# contents: read
138+
# id-token: write
139+
# pull-requests: read
140+
# uses: ./.github/workflows/report-fuzz-crash.yml
141+
# with:
142+
# fuzz_target: compress_gpu
143+
# crash_file: ${{ needs.gpu_compress_fuzz.outputs.first_crash_name }}
144+
# artifact_url: ${{ needs.gpu_compress_fuzz.outputs.artifact_url }}
145+
# artifact_name: compress_gpu-crash-artifacts
146+
# logs_artifact_name: compress_gpu-logs
147+
# branch: ${{ github.ref_name }}
148+
# commit: ${{ github.sha }}
149+
# secrets:
150+
# claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
151+
# gh_token: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/run-fuzzer.yml

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,21 @@ on:
1212
required: false
1313
type: number
1414
default: 7200
15+
family:
16+
description: "Runner family (e.g., m8g.large for CPU, g5+g4dn+g6 for GPU)"
17+
required: false
18+
type: string
19+
default: "m8g.large"
20+
image:
21+
description: "Runner image (e.g., ubuntu24-full-arm64, ubuntu24-gpu-x64)"
22+
required: false
23+
type: string
24+
default: "ubuntu24-full-arm64"
25+
extra_features:
26+
description: "Extra cargo features to enable (e.g., cuda)"
27+
required: false
28+
type: string
29+
default: ""
1530
outputs:
1631
crashes_found:
1732
description: "Whether crashes were found"
@@ -34,20 +49,15 @@ jobs:
3449
timeout-minutes: 230 # almost 4 hours
3550
runs-on:
3651
- runs-on=${{ github.run_id }}
37-
- family=m8g.large
38-
- image=ubuntu24-full-arm64
52+
- family=${{ inputs.family }}
53+
- image=${{ inputs.image }}
3954
- disk=large
4055
- extras=s3-cache
4156
- tag=${{ inputs.fuzz_target }}-fuzz
4257
outputs:
4358
crashes_found: ${{ steps.check.outputs.crashes_found }}
4459
first_crash_name: ${{ steps.check.outputs.first_crash_name }}
4560
artifact_url: ${{ steps.upload_artifacts.outputs.artifact-url }}
46-
env:
47-
AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
48-
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
49-
AWS_REGION: "us-east-1"
50-
AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
5161
steps:
5262
- uses: runs-on/action@v2
5363
with:
@@ -70,6 +80,11 @@ jobs:
7080

7181
- name: Restore corpus
7282
shell: bash
83+
env:
84+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
85+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
86+
AWS_REGION: "us-east-1"
87+
AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
7388
run: |
7489
CORPUS_KEY="${{ inputs.fuzz_target }}_corpus.tar.zst"
7590
CORPUS_DIR="fuzz/corpus/${{ inputs.fuzz_target }}"
@@ -99,8 +114,13 @@ jobs:
99114
- name: Run fuzzing target
100115
id: fuzz
101116
run: |
117+
FEATURES_FLAG=""
118+
if [ -n "${{ inputs.extra_features }}" ]; then
119+
FEATURES_FLAG="--features ${{ inputs.extra_features }}"
120+
fi
102121
RUSTFLAGS="--cfg vortex_nightly" RUST_BACKTRACE=1 \
103122
cargo +nightly fuzz run --release --debug-assertions \
123+
$FEATURES_FLAG \
104124
${{ inputs.fuzz_target }} -- \
105125
-max_total_time=${{ inputs.max_time }} -rss_limit_mb=0 \
106126
2>&1 | tee fuzz_output.log
@@ -149,6 +169,11 @@ jobs:
149169

150170
- name: Persist corpus
151171
shell: bash
172+
env:
173+
AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }}
174+
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }}
175+
AWS_REGION: "us-east-1"
176+
AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com"
152177
run: |
153178
CORPUS_KEY="${{ inputs.fuzz_target }}_corpus.tar.zst"
154179
CORPUS_DIR="fuzz/corpus/${{ inputs.fuzz_target }}"

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,3 @@ sweep.timestamp
229229

230230
# CUDA
231231
*.ptx
232-
233-
# nvCOMP SDK (downloaded at build time)
234-
vortex-cuda/nvcomp/sdk/

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ vortex-zstd = { version = "0.1.0", path = "./encodings/zstd", default-features =
271271

272272
# No version constraints for unpublished crates.
273273
vortex-bench = { path = "./vortex-bench", default-features = false }
274+
vortex-cuda = { path = "./vortex-cuda", default-features = false }
274275
vortex-duckdb = { path = "./vortex-duckdb", default-features = false }
275276

276277
[workspace.dependencies.getrandom_v03]

fuzz/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ default = ["native"]
2222
native = ["libfuzzer-sys", "zstd", "vortex-file", "vortex/files"]
2323
wasmfuzz = []
2424
zstd = ["vortex/zstd"]
25+
cuda = ["vortex-cuda", "tokio"]
2526

2627
[dependencies]
2728
# Always needed - arbitrary is used for input generation
@@ -48,6 +49,10 @@ vortex-utils = { workspace = true }
4849
libfuzzer-sys = { workspace = true, optional = true }
4950
vortex-file = { workspace = true, optional = true }
5051

52+
# GPU support dependencies (optional, only for CUDA fuzzing)
53+
tokio = { workspace = true, features = ["rt", "macros"], optional = true }
54+
vortex-cuda = { workspace = true, optional = true }
55+
5156
[lints]
5257
workspace = true
5358

@@ -82,3 +87,11 @@ name = "compress_roundtrip"
8287
path = "fuzz_targets/compress_roundtrip.rs"
8388
test = false
8489
required-features = ["native"]
90+
91+
[[bin]]
92+
bench = false
93+
doc = false
94+
name = "compress_gpu"
95+
path = "fuzz_targets/compress_gpu.rs"
96+
test = false
97+
required-features = ["native", "cuda"]

fuzz/build.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
use std::process::Command;
5+
6+
fn main() {
7+
// Declare the cfg so rustc doesn't warn about unexpected cfg.
8+
println!("cargo::rustc-check-cfg=cfg(cuda_available)");
9+
10+
// Only enable CUDA on Linux (matching vortex-cuda's behavior)
11+
if cfg!(not(target_os = "linux")) {
12+
return;
13+
}
14+
15+
// Check if nvcc is available
16+
if !cuda_available() {
17+
return;
18+
}
19+
20+
println!("cargo:rustc-cfg=cuda_available");
21+
}
22+
23+
fn cuda_available() -> bool {
24+
Command::new("nvcc").arg("--version").output().is_ok()
25+
}

fuzz/fuzz_targets/compress_gpu.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
#![no_main]
5+
#![allow(clippy::unwrap_used, clippy::result_large_err)]
6+
7+
use libfuzzer_sys::Corpus;
8+
use libfuzzer_sys::fuzz_target;
9+
use vortex_error::vortex_panic;
10+
use vortex_fuzz::FuzzCompressGpu;
11+
use vortex_fuzz::run_compress_gpu;
12+
13+
fuzz_target!(|fuzz: FuzzCompressGpu| -> Corpus {
14+
// Use tokio runtime to run async GPU fuzzer
15+
let rt = tokio::runtime::Builder::new_current_thread()
16+
.enable_all()
17+
.build()
18+
.unwrap();
19+
20+
match rt.block_on(run_compress_gpu(fuzz)) {
21+
Ok(true) => Corpus::Keep,
22+
Ok(false) => Corpus::Reject,
23+
Err(e) => {
24+
vortex_panic!("{e}");
25+
}
26+
}
27+
});

0 commit comments

Comments
 (0)