From 53c146a5d3ce866cef6bb8e5828899bd393a5a6c Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:19:39 +0000 Subject: [PATCH 01/10] feat[cuda]: to_host canonical Signed-off-by: Joe Isaacs --- vortex-cuda/src/canonical.rs | 64 ++++++++++++++++++++++++++++++++++++ vortex-cuda/src/lib.rs | 2 ++ 2 files changed, 66 insertions(+) create mode 100644 vortex-cuda/src/canonical.rs diff --git a/vortex-cuda/src/canonical.rs b/vortex-cuda/src/canonical.rs new file mode 100644 index 00000000000..4dc417f1165 --- /dev/null +++ b/vortex-cuda/src/canonical.rs @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use async_trait::async_trait; +use vortex_array::Canonical; +use vortex_array::arrays::BoolArray; +use vortex_array::arrays::BoolArrayParts; +use vortex_array::arrays::DecimalArray; +use vortex_array::arrays::DecimalArrayParts; +use vortex_array::arrays::PrimitiveArray; +use vortex_array::arrays::PrimitiveArrayParts; +use vortex_array::buffer::BufferHandle; +use vortex_error::VortexResult; + +/// Move all canonical data from to_host from device. +#[async_trait] +pub trait CanonicalCudaExt { + async fn to_host(self) -> VortexResult; +} + +impl CanonicalCudaExt for Canonical { + async fn to_host(self) -> VortexResult { + match self { + n @ Canonical::Null(_) => Ok(n), + Canonical::Bool(bool) => { + // NOTE: update to copy to host when adding buffer handle. + // Also update other method to copy validity to host. + let BoolArrayParts { bits, validity, .. } = bool.into_parts(); + Ok(Canonical::Bool(BoolArray::from_bit_buffer(bits, validity))) + } + Canonical::Primitive(prim) => { + let PrimitiveArrayParts { + ptype, + buffer, + validity, + .. + } = prim.into_parts(); + Ok(Canonical::Primitive(PrimitiveArray::from_byte_buffer( + buffer.try_into_host()?.await?, + ptype, + validity, + ))) + } + Canonical::Decimal(decimal) => { + let DecimalArrayParts { + decimal_dtype, + nullability, + values, + values_type, + validity, + } = decimal.into_parts(); + Ok(Canonical::Decimal(unsafe { + DecimalArray::new_unchecked_handle( + BufferHandle::new_host(values.try_into_host()?.await?), + values_type, + decimal_dtype, + validity, + ) + })) + } + _ => todo!(), + } + } +} diff --git a/vortex-cuda/src/lib.rs b/vortex-cuda/src/lib.rs index d77be685b20..c331dc80103 100644 --- a/vortex-cuda/src/lib.rs +++ b/vortex-cuda/src/lib.rs @@ -3,12 +3,14 @@ //! CUDA support for Vortex arrays. +mod canonical; mod device_buffer; pub mod executor; mod kernel; mod session; mod stream; +pub use canonical::CanonicalCudaExt; pub use device_buffer::CudaBufferExt; pub use device_buffer::CudaDeviceBuffer; pub use executor::CudaExecutionCtx; From 4abf4bd9dd14814c8b32989382dc628f49dfae06 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:37:20 +0000 Subject: [PATCH 02/10] feat[cuda]: to_host canonical Signed-off-by: Joe Isaacs --- vortex-cuda/src/canonical.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/vortex-cuda/src/canonical.rs b/vortex-cuda/src/canonical.rs index 4dc417f1165..7306c80aec1 100644 --- a/vortex-cuda/src/canonical.rs +++ b/vortex-cuda/src/canonical.rs @@ -15,9 +15,12 @@ use vortex_error::VortexResult; /// Move all canonical data from to_host from device. #[async_trait] pub trait CanonicalCudaExt { - async fn to_host(self) -> VortexResult; + async fn to_host(self) -> VortexResult + where + Self: Sized; } +#[async_trait] impl CanonicalCudaExt for Canonical { async fn to_host(self) -> VortexResult { match self { @@ -44,10 +47,10 @@ impl CanonicalCudaExt for Canonical { Canonical::Decimal(decimal) => { let DecimalArrayParts { decimal_dtype, - nullability, values, values_type, validity, + .. } = decimal.into_parts(); Ok(Canonical::Decimal(unsafe { DecimalArray::new_unchecked_handle( From a0678358962309aeb740ceddf354fb28b6d7bae2 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:22:16 +0000 Subject: [PATCH 03/10] wip Signed-off-by: Joe Isaacs --- Cargo.lock | 2 ++ fuzz/Cargo.toml | 5 +++++ fuzz/build.rs | 26 ++++++++++++++++++++++++++ fuzz/src/lib.rs | 8 ++++++++ 4 files changed, 41 insertions(+) create mode 100644 fuzz/build.rs diff --git a/Cargo.lock b/Cargo.lock index 55984f4d702..43b31e21b6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10639,10 +10639,12 @@ dependencies = [ "itertools 0.14.0", "libfuzzer-sys", "strum 0.27.2", + "tokio", "vortex", "vortex-array", "vortex-btrblocks", "vortex-buffer", + "vortex-cuda", "vortex-dtype", "vortex-error", "vortex-file", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index a9e2119bdb4..a95400b4431 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -22,6 +22,7 @@ default = ["native"] native = ["libfuzzer-sys", "zstd", "vortex-file", "vortex/files"] wasmfuzz = [] zstd = ["vortex/zstd"] +cuda = ["vortex-cuda", "tokio"] [dependencies] # Always needed - arbitrary is used for input generation @@ -48,6 +49,10 @@ vortex-utils = { workspace = true } libfuzzer-sys = { workspace = true, optional = true } vortex-file = { workspace = true, optional = true } +# GPU support dependencies (optional, only for CUDA fuzzing) +vortex-cuda = { path = "../vortex-cuda", optional = true } +tokio = { workspace = true, features = ["rt", "macros"], optional = true } + [lints] workspace = true diff --git a/fuzz/build.rs b/fuzz/build.rs new file mode 100644 index 00000000000..4d2804cdb2e --- /dev/null +++ b/fuzz/build.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use std::process::Command; + +fn main() { + // Declare the cfg so rustc doesn't warn about unexpected cfg. + println!("cargo::rustc-check-cfg=cfg(cuda_available)"); + + // Only enable CUDA on Linux (matching vortex-cuda's behavior) + if cfg!(not(target_os = "linux")) { + return; + } + + // Check if nvcc is available + if has_nvcc() { + println!("cargo:rustc-cfg=cuda_available"); + } +} + +fn has_nvcc() -> bool { + Command::new("nvcc") + .arg("--version") + .output() + .is_ok_and(|o| o.status.success()) +} diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index dd0b3022642..ccc30f2ef88 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -10,6 +10,10 @@ pub mod error; // File module only available for native builds (requires vortex-file which uses tokio) #[cfg(not(target_arch = "wasm32"))] pub mod file; + +// GPU module only available when CUDA is available +#[cfg(cuda_available)] +pub mod gpu; pub use array::Action; pub use array::CompressorStrategy; pub use array::ExpectedValue; @@ -20,6 +24,10 @@ pub use compress::FuzzCompressRoundtrip; pub use compress::run_compress_roundtrip; #[cfg(not(target_arch = "wasm32"))] pub use file::FuzzFileAction; +#[cfg(cuda_available)] +pub use gpu::FuzzCompressGpu; +#[cfg(cuda_available)] +pub use gpu::run_compress_gpu; // Runtime initialization - platform-specific #[cfg(not(target_arch = "wasm32"))] From 96a0286db34dca94396d93d4f4066547ffb12b25 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:34:47 +0000 Subject: [PATCH 04/10] wip Signed-off-by: Joe Isaacs --- .github/workflows/fuzz.yml | 39 ++++++ .github/workflows/run-fuzzer.yml | 24 +++- fuzz/Cargo.toml | 8 ++ fuzz/fuzz_targets/compress_gpu.rs | 27 ++++ fuzz/src/gpu/mod.rs | 202 ++++++++++++++++++++++++++++++ fuzz/src/lib.rs | 2 +- 6 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 fuzz/fuzz_targets/compress_gpu.rs create mode 100644 fuzz/src/gpu/mod.rs diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 9a07cd281a2..d85b2023148 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -21,6 +21,8 @@ jobs: uses: ./.github/workflows/run-fuzzer.yml with: fuzz_target: file_io + family: "m8g.large" + image: "ubuntu24-full-arm64" secrets: R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} @@ -106,3 +108,40 @@ jobs: secrets: R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} + + # ============================================================================ + # GPU Compress Fuzzer (CUDA) + # ============================================================================ + gpu_compress_fuzz: + name: "GPU Compress Fuzz" + uses: ./.github/workflows/run-fuzzer.yml + with: + fuzz_target: compress_gpu + family: "g5+g4dn+g6" + image: "ubuntu24-gpu-x64" + extra_features: "cuda" + secrets: + R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} + R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} + + report-gpu-compress-fuzz-failures: + name: "Report GPU Compress Fuzz Failures" + needs: gpu_compress_fuzz + if: always() && needs.gpu_compress_fuzz.outputs.crashes_found == 'true' + permissions: + issues: write + contents: read + id-token: write + pull-requests: read + uses: ./.github/workflows/report-fuzz-crash.yml + with: + fuzz_target: compress_gpu + crash_file: ${{ needs.gpu_compress_fuzz.outputs.first_crash_name }} + artifact_url: ${{ needs.gpu_compress_fuzz.outputs.artifact_url }} + artifact_name: compress_gpu-crash-artifacts + logs_artifact_name: compress_gpu-logs + branch: ${{ github.ref_name }} + commit: ${{ github.sha }} + secrets: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + gh_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/run-fuzzer.yml b/.github/workflows/run-fuzzer.yml index 302555d7b54..376ffc68ee6 100644 --- a/.github/workflows/run-fuzzer.yml +++ b/.github/workflows/run-fuzzer.yml @@ -12,6 +12,21 @@ on: required: false type: number default: 7200 + family: + description: "Runner family (e.g., m8g.large for CPU, g5+g4dn+g6 for GPU)" + required: false + type: string + default: "m8g.large" + image: + description: "Runner image (e.g., ubuntu24-full-arm64, ubuntu24-gpu-x64)" + required: false + type: string + default: "ubuntu24-full-arm64" + extra_features: + description: "Extra cargo features to enable (e.g., cuda)" + required: false + type: string + default: "" outputs: crashes_found: description: "Whether crashes were found" @@ -34,8 +49,8 @@ jobs: timeout-minutes: 230 # almost 4 hours runs-on: - runs-on=${{ github.run_id }} - - family=m8g.large - - image=ubuntu24-full-arm64 + - family=${{ inputs.family }} + - image=${{ inputs.image }} - disk=large - extras=s3-cache - tag=${{ inputs.fuzz_target }}-fuzz @@ -99,8 +114,13 @@ jobs: - name: Run fuzzing target id: fuzz run: | + FEATURES_FLAG="" + if [ -n "${{ inputs.extra_features }}" ]; then + FEATURES_FLAG="--features ${{ inputs.extra_features }}" + fi RUSTFLAGS="--cfg vortex_nightly" RUST_BACKTRACE=1 \ cargo +nightly fuzz run --release --debug-assertions \ + $FEATURES_FLAG \ ${{ inputs.fuzz_target }} -- \ -max_total_time=${{ inputs.max_time }} -rss_limit_mb=0 \ 2>&1 | tee fuzz_output.log diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index a95400b4431..52281611140 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -87,3 +87,11 @@ name = "compress_roundtrip" path = "fuzz_targets/compress_roundtrip.rs" test = false required-features = ["native"] + +[[bin]] +bench = false +doc = false +name = "compress_gpu" +path = "fuzz_targets/compress_gpu.rs" +test = false +required-features = ["native", "cuda"] diff --git a/fuzz/fuzz_targets/compress_gpu.rs b/fuzz/fuzz_targets/compress_gpu.rs new file mode 100644 index 00000000000..eea7ff6c5e3 --- /dev/null +++ b/fuzz/fuzz_targets/compress_gpu.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +#![no_main] +#![allow(clippy::unwrap_used, clippy::result_large_err)] + +use libfuzzer_sys::Corpus; +use libfuzzer_sys::fuzz_target; +use vortex_error::vortex_panic; +use vortex_fuzz::FuzzCompressGpu; +use vortex_fuzz::run_compress_gpu; + +fuzz_target!(|fuzz: FuzzCompressGpu| -> Corpus { + // Use tokio runtime to run async GPU fuzzer + let rt = tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap(); + + match rt.block_on(run_compress_gpu(fuzz)) { + Ok(true) => Corpus::Keep, + Ok(false) => Corpus::Reject, + Err(e) => { + vortex_panic!("{e}"); + } + } +}); diff --git a/fuzz/src/gpu/mod.rs b/fuzz/src/gpu/mod.rs new file mode 100644 index 00000000000..8213546d7b9 --- /dev/null +++ b/fuzz/src/gpu/mod.rs @@ -0,0 +1,202 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! GPU fuzzer module for testing CUDA decompression. +//! +//! This module generates arbitrary instances of GPU-supported compressed encodings, +//! then verifies that GPU decompression produces the same results as CPU decompression. + +use arbitrary::Arbitrary; +use arbitrary::Result; +use arbitrary::Unstructured; +use vortex_array::ArrayRef; +use vortex_array::IntoArray; +use vortex_array::arrays::ArbitraryDictArray; +use vortex_dtype::Nullability; +use vortex_dtype::PType; + +use crate::error::VortexFuzzResult; + +/// Which GPU-supported encoding to generate. +#[derive(Debug, Clone, Copy)] +pub enum GpuEncodingKind { + /// Dictionary encoding with GPU take support. + Dict, +} + +impl<'a> Arbitrary<'a> for GpuEncodingKind { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + // Currently only Dict is supported + match u.int_in_range(0..=0)? { + 0 => Ok(GpuEncodingKind::Dict), + _ => unreachable!(), + } + } +} + +/// Input for the GPU decompression fuzzer. +#[derive(Debug)] +pub struct FuzzCompressGpu { + pub array: ArrayRef, +} + +impl<'a> Arbitrary<'a> for FuzzCompressGpu { + fn arbitrary(u: &mut Unstructured<'a>) -> Result { + let kind: GpuEncodingKind = u.arbitrary()?; + + let array = match kind { + GpuEncodingKind::Dict => { + // Dict already has Arbitrary support, use primitive values for GPU compatibility + let dtype = arbitrary_gpu_primitive_dtype(u)?; + ArbitraryDictArray::with_dtype(u, &dtype, None)? + .0 + .into_array() + } + }; + + Ok(FuzzCompressGpu { array }) + } +} + +/// Generate a random primitive DType suitable for GPU operations. +fn arbitrary_gpu_primitive_dtype(u: &mut Unstructured) -> Result { + let nullability: Nullability = u.arbitrary()?; + let ptype = match u.int_in_range(0..=9)? { + 0 => PType::U8, + 1 => PType::U16, + 2 => PType::U32, + 3 => PType::U64, + 4 => PType::I8, + 5 => PType::I16, + 6 => PType::I32, + 7 => PType::I64, + 8 => PType::F32, + 9 => PType::F64, + _ => unreachable!(), + }; + Ok(vortex_dtype::DType::Primitive(ptype, nullability)) +} + +/// Run the GPU decompression fuzzer. +/// +/// This function: +/// 1. Decompresses the array on CPU (reference) +/// 2. Decompresses the array on GPU +/// 3. Copies GPU result back to host using `CanonicalCudaExt::to_host` +/// 4. Compares the results +/// +/// Returns: +/// - `Ok(true)` - test passed, keep in corpus +/// - `Ok(false)` - test skipped (e.g., no CUDA), reject from corpus +/// - `Err(_)` - a bug was found +#[cfg(cuda_available)] +#[allow(clippy::result_large_err)] +pub async fn run_compress_gpu(fuzz: FuzzCompressGpu) -> VortexFuzzResult { + use vortex_array::Array; + use vortex_array::ToCanonical; + use vortex_cuda::CanonicalCudaExt; + use vortex_cuda::CudaSession; + use vortex_cuda::executor::CudaArrayExt; + use vortex_cuda::initialize_cuda; + use vortex_session::VortexSession; + + use crate::error::Backtrace; + use crate::error::VortexFuzzError; + + let FuzzCompressGpu { array } = fuzz; + + // Store original properties for error reporting + let original_len = array.len(); + + // 1. CPU decompression (reference) + let cpu_canonical = match array.to_canonical() { + Ok(c) => c, + Err(e) => { + return Err(VortexFuzzError::VortexError(e, Backtrace::capture())); + } + }; + + // 2. Create CUDA execution context + let session = VortexSession::default(); + initialize_cuda(session.cuda_session().as_ref()); + + let mut cuda_ctx = match CudaSession::create_execution_ctx(session) { + Ok(ctx) => ctx, + Err(e) => { + return Err(VortexFuzzError::VortexError(e, Backtrace::capture())); + } + }; + + // 3. GPU decompression + let gpu_canonical = match array.clone().execute_cuda(&mut cuda_ctx).await { + Ok(c) => c, + Err(e) => { + return Err(VortexFuzzError::VortexError(e, Backtrace::capture())); + } + }; + + // 4. Copy GPU result back to host using CanonicalCudaExt + let gpu_host_canonical = match gpu_canonical.to_host().await { + Ok(c) => c, + Err(e) => { + return Err(VortexFuzzError::VortexError(e, Backtrace::capture())); + } + }; + + // 5. Compare canonicals + let cpu_array = cpu_canonical.into_array(); + let gpu_array = gpu_host_canonical.into_array(); + + // Verify dtype is preserved + if cpu_array.dtype() != gpu_array.dtype() { + return Err(VortexFuzzError::DTypeMismatch( + cpu_array, + gpu_array, + 0, + Backtrace::capture(), + )); + } + + // Verify length is preserved + if original_len != gpu_array.len() { + return Err(VortexFuzzError::LengthMismatch( + original_len, + gpu_array.len(), + array, + gpu_array, + 0, + Backtrace::capture(), + )); + } + + // Compare element by element + for i in 0..original_len { + let cpu_scalar = cpu_array + .scalar_at(i) + .map_err(|e| VortexFuzzError::VortexError(e, Backtrace::capture()))?; + let gpu_scalar = gpu_array + .scalar_at(i) + .map_err(|e| VortexFuzzError::VortexError(e, Backtrace::capture()))?; + + if cpu_scalar != gpu_scalar { + return Err(VortexFuzzError::ArrayNotEqual( + cpu_scalar, + gpu_scalar, + i, + cpu_array, + gpu_array, + 0, + Backtrace::capture(), + )); + } + } + + Ok(true) +} + +/// No-op fallback when CUDA is not available. +#[cfg(not(cuda_available))] +pub async fn run_compress_gpu(_fuzz: FuzzCompressGpu) -> VortexFuzzResult { + // Reject from corpus when CUDA is not available + Ok(false) +} diff --git a/fuzz/src/lib.rs b/fuzz/src/lib.rs index ccc30f2ef88..91c75d4018d 100644 --- a/fuzz/src/lib.rs +++ b/fuzz/src/lib.rs @@ -11,7 +11,7 @@ pub mod error; #[cfg(not(target_arch = "wasm32"))] pub mod file; -// GPU module only available when CUDA is available +// GPU fuzzer module (only available when CUDA is available) #[cfg(cuda_available)] pub mod gpu; pub use array::Action; From f8efeb8dce194cb1ed689ba692d76d85b2b177b2 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:35:47 +0000 Subject: [PATCH 05/10] wip Signed-off-by: Joe Isaacs --- .github/workflows/fuzz.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index d85b2023148..cdd16f0989c 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -71,6 +71,8 @@ jobs: uses: ./.github/workflows/run-fuzzer.yml with: fuzz_target: array_ops + family: "m8g.large" + image: "ubuntu24-full-arm64" secrets: R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} @@ -105,6 +107,8 @@ jobs: uses: ./.github/workflows/run-fuzzer.yml with: fuzz_target: compress_roundtrip + family: "m8g.large" + image: "ubuntu24-full-arm64" secrets: R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} From 9125f9071559e9fc666dfc7097a77d5b200ef9e0 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:38:07 +0000 Subject: [PATCH 06/10] wip Signed-off-by: Joe Isaacs --- .github/workflows/fuzz.yml | 42 +++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index cdd16f0989c..7d608bf3675 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -128,24 +128,24 @@ jobs: R2_FUZZ_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} R2_FUZZ_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} - report-gpu-compress-fuzz-failures: - name: "Report GPU Compress Fuzz Failures" - needs: gpu_compress_fuzz - if: always() && needs.gpu_compress_fuzz.outputs.crashes_found == 'true' - permissions: - issues: write - contents: read - id-token: write - pull-requests: read - uses: ./.github/workflows/report-fuzz-crash.yml - with: - fuzz_target: compress_gpu - crash_file: ${{ needs.gpu_compress_fuzz.outputs.first_crash_name }} - artifact_url: ${{ needs.gpu_compress_fuzz.outputs.artifact_url }} - artifact_name: compress_gpu-crash-artifacts - logs_artifact_name: compress_gpu-logs - branch: ${{ github.ref_name }} - commit: ${{ github.sha }} - secrets: - claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} - gh_token: ${{ secrets.GITHUB_TOKEN }} +# report-gpu-compress-fuzz-failures: +# name: "Report GPU Compress Fuzz Failures" +# needs: gpu_compress_fuzz +# if: always() && needs.gpu_compress_fuzz.outputs.crashes_found == 'true' +# permissions: +# issues: write +# contents: read +# id-token: write +# pull-requests: read +# uses: ./.github/workflows/report-fuzz-crash.yml +# with: +# fuzz_target: compress_gpu +# crash_file: ${{ needs.gpu_compress_fuzz.outputs.first_crash_name }} +# artifact_url: ${{ needs.gpu_compress_fuzz.outputs.artifact_url }} +# artifact_name: compress_gpu-crash-artifacts +# logs_artifact_name: compress_gpu-logs +# branch: ${{ github.ref_name }} +# commit: ${{ github.sha }} +# secrets: +# claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} +# gh_token: ${{ secrets.GITHUB_TOKEN }} From ebab8bc0e69b8092bf57950e4be90eaf57a0e756 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 19:47:57 +0000 Subject: [PATCH 07/10] wip Signed-off-by: Joe Isaacs --- .github/workflows/fuzz.yml | 2 +- .github/workflows/run-fuzzer.yml | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml index 7d608bf3675..1c48a31c7df 100644 --- a/.github/workflows/fuzz.yml +++ b/.github/workflows/fuzz.yml @@ -121,7 +121,7 @@ jobs: uses: ./.github/workflows/run-fuzzer.yml with: fuzz_target: compress_gpu - family: "g5+g4dn+g6" + family: "g4dn" image: "ubuntu24-gpu-x64" extra_features: "cuda" secrets: diff --git a/.github/workflows/run-fuzzer.yml b/.github/workflows/run-fuzzer.yml index 376ffc68ee6..c649b951256 100644 --- a/.github/workflows/run-fuzzer.yml +++ b/.github/workflows/run-fuzzer.yml @@ -58,11 +58,6 @@ jobs: crashes_found: ${{ steps.check.outputs.crashes_found }} first_crash_name: ${{ steps.check.outputs.first_crash_name }} artifact_url: ${{ steps.upload_artifacts.outputs.artifact-url }} - env: - AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} - AWS_REGION: "us-east-1" - AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com" steps: - uses: runs-on/action@v2 with: @@ -85,6 +80,11 @@ jobs: - name: Restore corpus shell: bash + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} + AWS_REGION: "us-east-1" + AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com" run: | CORPUS_KEY="${{ inputs.fuzz_target }}_corpus.tar.zst" CORPUS_DIR="fuzz/corpus/${{ inputs.fuzz_target }}" @@ -169,6 +169,11 @@ jobs: - name: Persist corpus shell: bash + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_FUZZ_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_FUZZ_SECRET_ACCESS_KEY }} + AWS_REGION: "us-east-1" + AWS_ENDPOINT_URL: "https://01e9655179bbec953276890b183039bc.r2.cloudflarestorage.com" run: | CORPUS_KEY="${{ inputs.fuzz_target }}_corpus.tar.zst" CORPUS_DIR="fuzz/corpus/${{ inputs.fuzz_target }}" From bbe344e7bbc405789cb75b1cf3cec53f12beaecc Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 22:04:59 +0000 Subject: [PATCH 08/10] wip Signed-off-by: Joe Isaacs --- fuzz/src/gpu/mod.rs | 3 +-- vortex-array/src/arrays/primitive/compute/take/avx2.rs | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzz/src/gpu/mod.rs b/fuzz/src/gpu/mod.rs index 8213546d7b9..5f2cc08f1bc 100644 --- a/fuzz/src/gpu/mod.rs +++ b/fuzz/src/gpu/mod.rs @@ -93,7 +93,6 @@ fn arbitrary_gpu_primitive_dtype(u: &mut Unstructured) -> Result VortexFuzzResult { use vortex_array::Array; - use vortex_array::ToCanonical; use vortex_cuda::CanonicalCudaExt; use vortex_cuda::CudaSession; use vortex_cuda::executor::CudaArrayExt; @@ -117,7 +116,7 @@ pub async fn run_compress_gpu(fuzz: FuzzCompressGpu) -> VortexFuzzResult { }; // 2. Create CUDA execution context - let session = VortexSession::default(); + let session = VortexSession::empty(); initialize_cuda(session.cuda_session().as_ref()); let mut cuda_ctx = match CudaSession::create_execution_ctx(session) { diff --git a/vortex-array/src/arrays/primitive/compute/take/avx2.rs b/vortex-array/src/arrays/primitive/compute/take/avx2.rs index c330a9226a3..5f46d626718 100644 --- a/vortex-array/src/arrays/primitive/compute/take/avx2.rs +++ b/vortex-array/src/arrays/primitive/compute/take/avx2.rs @@ -48,6 +48,7 @@ impl TakeImpl for TakeKernelAVX2 { /// /// The caller must ensure that if the validity has a length, it is the same length as the indices, /// and that the `avx2` feature is enabled. +#[allow(unused)] #[target_feature(enable = "avx2")] unsafe fn take_primitive_avx2( values: &[V], From fd31ebfebbcc29d74d867313384f8d7d432cd71b Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 22:39:30 +0000 Subject: [PATCH 09/10] wip Signed-off-by: Joe Isaacs --- fuzz/src/gpu/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/fuzz/src/gpu/mod.rs b/fuzz/src/gpu/mod.rs index 5f2cc08f1bc..8ad8f372969 100644 --- a/fuzz/src/gpu/mod.rs +++ b/fuzz/src/gpu/mod.rs @@ -97,6 +97,7 @@ pub async fn run_compress_gpu(fuzz: FuzzCompressGpu) -> VortexFuzzResult { use vortex_cuda::CudaSession; use vortex_cuda::executor::CudaArrayExt; use vortex_cuda::initialize_cuda; + use vortex_cuda::session::CudaSessionExt; use vortex_session::VortexSession; use crate::error::Backtrace; From dd78d60662ccf57b586d455da668ec409230ba25 Mon Sep 17 00:00:00 2001 From: Joe Isaacs Date: Fri, 23 Jan 2026 22:45:30 +0000 Subject: [PATCH 10/10] wip Signed-off-by: Joe Isaacs --- fuzz/src/gpu/mod.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fuzz/src/gpu/mod.rs b/fuzz/src/gpu/mod.rs index 8ad8f372969..fac00bbe1a3 100644 --- a/fuzz/src/gpu/mod.rs +++ b/fuzz/src/gpu/mod.rs @@ -120,12 +120,9 @@ pub async fn run_compress_gpu(fuzz: FuzzCompressGpu) -> VortexFuzzResult { let session = VortexSession::empty(); initialize_cuda(session.cuda_session().as_ref()); - let mut cuda_ctx = match CudaSession::create_execution_ctx(session) { - Ok(ctx) => ctx, - Err(e) => { - return Err(VortexFuzzError::VortexError(e, Backtrace::capture())); - } - }; + let mut cuda_ctx = session + .create_execution_ctx() + .vortex_expect("cannot create session"); // 3. GPU decompression let gpu_canonical = match array.clone().execute_cuda(&mut cuda_ctx).await {