From 330a30a8e9fd8ed3ead461657417724c9f8d9af5 Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Mon, 14 Sep 2026 14:53:32 +0000 Subject: [PATCH 1/2] add CodeQL, Trivy and Clippy checks --- .github/workflows/basic.yml | 18 +++++++++ .github/workflows/codeql.yml | 74 ++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 .github/workflows/codeql.yml diff --git a/.github/workflows/basic.yml b/.github/workflows/basic.yml index 370b3ef..4ebab37 100644 --- a/.github/workflows/basic.yml +++ b/.github/workflows/basic.yml @@ -66,6 +66,9 @@ jobs: git ls-files -z -- ':(glob)**/*.cpp' ':(glob)**/*.hpp' ':(glob)**/*.h' \ | xargs -0 --no-run-if-empty clang-format --dry-run --Werror + - name: Run Clippy + run: cargo clippy --workspace --all-targets -- -D warnings + - name: Build run: cargo build --verbose @@ -102,6 +105,21 @@ jobs: name: documentation path: target/doc + trivy: + name: Trivy scan + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Scan repository with Trivy + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 + with: + scan-type: fs + scan-ref: . + scanners: vuln,secret,misconfig + exit-code: 1 + deploy-documentation: if: (github.event_name == 'push' && github.ref == 'refs/heads/main') || (github.event_name == 'workflow_dispatch' && inputs.deploy_documentation == 'true') needs: build-and-test diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..611810b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,74 @@ +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: "0 15 * * 0" # Every Sunday at 15:00 UTC + +permissions: + contents: read + +jobs: + analyze: + name: "Analyze (${{ matrix.language }})" + runs-on: ["oneapi-rs", "Linux"] + + permissions: + actions: read + contents: read + packages: read + security-events: write + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: manual + - language: rust + build-mode: none + + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Check if oneAPI is already installed + id: check-oneapi + run: | + if [ -f /home/test-user/intel/oneapi/setvars.sh ]; then + echo "installed=true" >> $GITHUB_OUTPUT + source /home/test-user/intel/oneapi/setvars.sh + printenv | grep -E '^(PATH|LD_LIBRARY_PATH|LIBRARY_PATH|CPATH|C_INCLUDE_PATH|CPLUS_INCLUDE_PATH)=' >> $GITHUB_ENV + else + echo "installed=false" >> $GITHUB_OUTPUT + fi + + - name: Setup oneAPI + if: steps.check-oneapi.outputs.installed != 'true' + run: | + installer="intel-oneapi-toolkit-2026.1.0.192_offline.sh" + checksum="9d969de9cafbb698bf50f088c4b5174b50fc816f504049e685d6f6d198e10dbc17ef2cd4cfb0bc2b3d2179644a8d77d1" + curl --fail --location --retry 3 --silent --show-error --output "$installer" \ + "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/33cb2a22-ddf1-4aa9-8d68-1f5a118acaf2/intel-oneapi-toolkit-2026.1.0.192_offline.sh" + echo "$checksum $installer" | sha384sum --check + sh "./$installer" -a --silent --cli --eula accept + + source /home/test-user/intel/oneapi/setvars.sh + printenv | grep -E '^(PATH|LD_LIBRARY_PATH|LIBRARY_PATH|CPATH|C_INCLUDE_PATH|CPLUS_INCLUDE_PATH)=' >> $GITHUB_ENV + + - name: Initialize CodeQL + uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Build + run: cargo build --verbose + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + with: + category: "/language:${{ matrix.language }}" From 840c048271d484a2f559e7d90f3e9d9b7e7dc38a Mon Sep 17 00:00:00 2001 From: Rafal Rudnicki Date: Tue, 15 Sep 2026 14:54:08 +0000 Subject: [PATCH 2/2] Fix Clippy findings --- sycl/sycl-rs-sys/build.rs | 2 +- sycl/sycl-rs-sys/src/event-sys.rs | 16 +++++++-- sycl/sycl-rs-sys/src/queue-sys.rs | 23 +++++++++++++ sycl/sycl-rs-sys/src/types-sys.rs | 8 ++++- sycl/sycl-rs-sys/src/usm-sys.rs | 18 ++++++++++ sycl/sycl-rs/examples/kernel_launch.rs | 2 +- sycl/sycl-rs/examples/kernel_launch_derive.rs | 2 +- sycl/sycl-rs/src/event.rs | 2 +- sycl/sycl-rs/src/kernel.rs | 16 ++++++--- sycl/sycl-rs/src/queue.rs | 33 +++++++++++++++---- sycl/sycl-rs/src/range.rs | 4 +++ sycl/sycl-rs/src/usm.rs | 13 ++++++-- sycl/sycl-rs/src/usmbox.rs | 2 +- 13 files changed, 119 insertions(+), 22 deletions(-) diff --git a/sycl/sycl-rs-sys/build.rs b/sycl/sycl-rs-sys/build.rs index 5c6e089..90cdf1a 100644 --- a/sycl/sycl-rs-sys/build.rs +++ b/sycl/sycl-rs-sys/build.rs @@ -54,7 +54,7 @@ fn main() { "include/kernel-bundle.hpp", ]; - cxx_build::bridges(&rust_sources) + cxx_build::bridges(rust_sources) .compiler(&compiler_path) .flag("-fsycl") .files(&cpp_sources) diff --git a/sycl/sycl-rs-sys/src/event-sys.rs b/sycl/sycl-rs-sys/src/event-sys.rs index c995da0..0d30504 100644 --- a/sycl/sycl-rs-sys/src/event-sys.rs +++ b/sycl/sycl-rs-sys/src/event-sys.rs @@ -10,6 +10,8 @@ use std::sync::{Arc, atomic::Ordering::Relaxed}; use crate::types::SharedWaker; +// WA for Clippy issue https://github.com/rust-lang/rust-clippy/issues/16317 +#[allow(clippy::missing_safety_doc)] #[cxx::bridge(namespace = "sycl_shims::event")] pub mod ffi { #[namespace = "sycl_shims"] @@ -29,6 +31,10 @@ pub mod ffi { fn wait(event: &mut UniquePtr) -> Result<()>; + /// # Safety + /// + /// `waker` must come from `Arc::into_raw` and transfer one strong reference to the + /// callback, which will consume it after the event completes. unsafe fn register_callback( queue: &mut UniquePtr, event: &Event, @@ -41,12 +47,18 @@ pub mod ffi { extern "Rust" { type SharedWaker; + /// # Safety + /// + /// `ptr` must come from `Arc::into_raw` and represent a strong reference owned by this + /// callback. unsafe fn wake(ptr: *const SharedWaker); } } -// Safety: SharedWaker must by a pointer created by Arc::into_raw. The caller must increment the -// SharedWaker's strong reference count before calling. +/// # Safety +/// +/// SharedWaker must be a pointer created by Arc::into_raw. The caller must increment the +/// SharedWaker's strong reference count before calling. unsafe fn wake(ptr: *const SharedWaker) { unsafe { (*ptr).done.store(true, Relaxed); diff --git a/sycl/sycl-rs-sys/src/queue-sys.rs b/sycl/sycl-rs-sys/src/queue-sys.rs index 79f040b..2310585 100644 --- a/sycl/sycl-rs-sys/src/queue-sys.rs +++ b/sycl/sycl-rs-sys/src/queue-sys.rs @@ -6,6 +6,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // +// WA for Clippy issue https://github.com/rust-lang/rust-clippy/issues/16317 +#[allow(clippy::missing_safety_doc)] #[cxx::bridge(namespace = "sycl_shims::queue")] pub mod ffi { #[namespace = "sycl_shims"] @@ -44,6 +46,10 @@ pub mod ffi { fn clone(queue: &Queue) -> UniquePtr; + /// # Safety + /// + /// `ptr` must be valid for writes of `num_bytes` bytes and remain valid until the + /// returned event completes. The memory must not be accessed concurrently. unsafe fn memset( queue: &mut UniquePtr, ptr: *mut u8, @@ -52,6 +58,11 @@ pub mod ffi { dep_events: Vec, ) -> Result>; + /// # Safety + /// + /// `src` and `dest` must be valid for reads and writes, respectively, of `num_bytes` + /// bytes and remain valid until the returned event completes. The regions must not + /// overlap or be accessed concurrently. unsafe fn memcpy( queue: &mut UniquePtr, dest: *mut u8, @@ -67,6 +78,10 @@ pub mod ffi { fn wait(queue: &mut UniquePtr) -> Result<()>; + /// # Safety + /// + /// Each entry in `args` must match the corresponding kernel parameter's size, layout, + /// and alignment. unsafe fn launch_1d( queue: &mut UniquePtr, global_size: Range1, @@ -75,6 +90,10 @@ pub mod ffi { args: &[&[u8]], ) -> Result>; + /// # Safety + /// + /// Each entry in `args` must match the corresponding kernel parameter's size, layout, + /// and alignment. unsafe fn launch_2d( queue: &mut UniquePtr, global_size: Range2, @@ -83,6 +102,10 @@ pub mod ffi { args: &[&[u8]], ) -> Result>; + /// # Safety + /// + /// Each entry in `args` must match the corresponding kernel parameter's size, layout, + /// and alignment. unsafe fn launch_3d( queue: &mut UniquePtr, global_size: Range3, diff --git a/sycl/sycl-rs-sys/src/types-sys.rs b/sycl/sycl-rs-sys/src/types-sys.rs index 2bbdb6f..3136ca6 100644 --- a/sycl/sycl-rs-sys/src/types-sys.rs +++ b/sycl/sycl-rs-sys/src/types-sys.rs @@ -24,6 +24,12 @@ impl SharedWaker { } } +impl Default for SharedWaker { + fn default() -> Self { + Self::new() + } +} + #[cxx::bridge(namespace = "sycl_shims")] pub mod ffi { unsafe extern "C++" { @@ -58,7 +64,7 @@ pub mod ffi { enum Aspect { /// Indicates that the device supports the `PciBdfAddress` information descriptor. ExtIntelPciAddress, - /// Indicates that the implementation identifies this device as integrated GPU. + /// Indicates that the implementation identifies this device as an integrated GPU. ExtOneapiIsIntegratedGpu, } diff --git a/sycl/sycl-rs-sys/src/usm-sys.rs b/sycl/sycl-rs-sys/src/usm-sys.rs index e68a20c..b727909 100644 --- a/sycl/sycl-rs-sys/src/usm-sys.rs +++ b/sycl/sycl-rs-sys/src/usm-sys.rs @@ -6,6 +6,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 // +// WA for Clippy issue https://github.com/rust-lang/rust-clippy/issues/16317 +#[allow(clippy::missing_safety_doc)] #[cxx::bridge(namespace = "sycl_shims::usm")] pub mod ffi { unsafe extern "C++" { @@ -15,21 +17,37 @@ pub mod ffi { extern "C++" { include!("sycl-rs-sys/include/usm.hpp"); + /// # Safety + /// + /// `queue` must refer to a valid SYCL queue and `alignment` must be a supported power of + /// two. The returned allocation must be released with `free` using a compatible queue. unsafe fn aligned_alloc_device( alignment: usize, num_bytes: usize, queue: &Queue, ) -> Result<*mut u8>; + /// # Safety + /// + /// `queue` must refer to a valid SYCL queue and `alignment` must be a supported power of + /// two. The returned allocation must be released with `free` using a compatible queue. unsafe fn aligned_alloc_host( alignment: usize, num_bytes: usize, queue: &Queue, ) -> Result<*mut u8>; + /// # Safety + /// + /// `queue` must refer to a valid SYCL queue and `alignment` must be a supported power of + /// two. The returned allocation must be released with `free` using a compatible queue. unsafe fn aligned_alloc_shared( alignment: usize, num_bytes: usize, queue: &Queue, ) -> Result<*mut u8>; + /// # Safety + /// + /// `ptr` must be a live USM allocation associated with `queue` and must not be used after + /// this call. unsafe fn free(ptr: *mut u8, queue: &Queue); } } diff --git a/sycl/sycl-rs/examples/kernel_launch.rs b/sycl/sycl-rs/examples/kernel_launch.rs index 57cc6c8..267b222 100644 --- a/sycl/sycl-rs/examples/kernel_launch.rs +++ b/sycl/sycl-rs/examples/kernel_launch.rs @@ -37,7 +37,7 @@ async fn main() -> sycl_rs::Result<()> { queue.launch( NdRange::new([1024], [16]), &kernel, - (f16::from_f32(3.14), &mut device_array), + (f16::PI, &mut device_array), ) }? .await?; diff --git a/sycl/sycl-rs/examples/kernel_launch_derive.rs b/sycl/sycl-rs/examples/kernel_launch_derive.rs index 5bbd64d..7b72b02 100644 --- a/sycl/sycl-rs/examples/kernel_launch_derive.rs +++ b/sycl/sycl-rs/examples/kernel_launch_derive.rs @@ -42,7 +42,7 @@ fn main() -> sycl_rs::Result<()> { NdRange::new([1024], [16]), &kernel, IotaArgs { - start: 3.14_f32, + start: std::f32::consts::PI, ptr: &mut array, }, ) diff --git a/sycl/sycl-rs/src/event.rs b/sycl/sycl-rs/src/event.rs index e0f85fd..8c094de 100644 --- a/sycl/sycl-rs/src/event.rs +++ b/sycl/sycl-rs/src/event.rs @@ -60,7 +60,7 @@ impl Future for EventFuture { let this = self.project(); // Set the callback on first Future poll (Futures can't be active until polled) - if *this.set_callback == false { + if !*this.set_callback { *this.set_callback = true; let mut queue = Queue::new_immediate(); this.shared.waker.register(cx.waker()); diff --git a/sycl/sycl-rs/src/kernel.rs b/sycl/sycl-rs/src/kernel.rs index afe052a..d1ce3a8 100644 --- a/sycl/sycl-rs/src/kernel.rs +++ b/sycl/sycl-rs/src/kernel.rs @@ -51,12 +51,16 @@ impl From> for Kernel { /// Types which can be passed as SYCL kernel arguments. /// -/// Safety: a type implement this trait must mirror the representation and alignment of the +/// # Safety +/// +/// A type implementing this trait must mirror the representation and alignment of the /// corresponding SYCL kernel argument structure. pub unsafe trait KernelArgument { /// Converts self to a raw byte representation. /// - /// Safety: This function returns a reference to raw bytes. These bytes will be passed to FFI + /// # Safety + /// + /// This function returns a reference to raw bytes. These bytes will be passed to FFI /// functions. The caller must make sure these functions respect Rust's aliasing rules. unsafe fn as_raw_arg(&self) -> &[u8]; } @@ -69,12 +73,16 @@ unsafe impl KernelArgument for T { /// Types which describe an argument list for a SYCL kernel. /// -/// Safety: a type implement this trait must mirror the representation and alignment of each +/// # Safety +/// +/// A type implementing this trait must mirror the representation and alignment of each /// corresponding SYCL kernel argument inside the returned array. pub unsafe trait KernelArgumentList { /// Converts each struct member to a raw byte representation. /// - /// Safety: This function returns references to raw bytes. These bytes will be passed to FFI + /// # Safety + /// + /// This function returns references to raw bytes. These bytes will be passed to FFI /// functions. The caller must make sure these functions respect Rust's aliasing rules. unsafe fn as_raw_arg_list(&self) -> [&[u8]; ARGC]; } diff --git a/sycl/sycl-rs/src/queue.rs b/sycl/sycl-rs/src/queue.rs index 7fefcaf..d0814e4 100644 --- a/sycl/sycl-rs/src/queue.rs +++ b/sycl/sycl-rs/src/queue.rs @@ -28,6 +28,8 @@ use crate::{ /// a kernel. pub struct Queue(pub(crate) cxx::UniquePtr); +// We intentionally do not implement Default for Queue as it could not always select the desired device. +#[allow(clippy::new_without_default)] impl Queue { /// Construct a `Queue` based on the device returned from the default selector. pub fn new() -> Self { @@ -77,28 +79,40 @@ impl Queue { } /// Allocates memory and creates a host-side [`UsmBox`] that can store an array of T. - /// Safety: the array contents are uninitialized. + /// + /// # Safety + /// + /// The array contents are uninitialized and must not be read before they are initialized. pub unsafe fn alloc_uninit_host(&self, len: usize) -> HostUsmBox { let allocator = UsmAllocator::from(self); unsafe { UsmBox::new(allocator, len) } } /// Allocates memory and creates a shared [`UsmBox`] that can store an array of T. - /// Safety: the array contents are uninitialized. + /// + /// # Safety + /// + /// The array contents are uninitialized and must not be read before they are initialized. pub unsafe fn alloc_uninit_shared(&self, len: usize) -> SharedUsmBox { let allocator = UsmAllocator::from(self); unsafe { UsmBox::new(allocator, len) } } /// Allocates memory and creates a device-side [`UsmBox`] that can store an array of T. - /// Safety: the array contents are uninitialized. + /// + /// # Safety + /// + /// The array contents are uninitialized and must not be read before they are initialized. pub unsafe fn alloc_uninit_device(&self, len: usize) -> DeviceUsmBox { let allocator = UsmAllocator::from(self); unsafe { UsmBox::new(allocator, len) } } /// Sets memory allocated with USM allocations. - /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else. + /// + /// # Safety + /// + /// The caller must ensure the underlying memory is not aliased elsewhere. pub unsafe fn memset( &mut self, array: &mut UsmBox, @@ -108,7 +122,10 @@ impl Queue { } /// Sets memory allocated with USM allocations after all specified events finish. - /// Safety: the caller must make sure the underlying memory isn't being aliased somewhere else. + /// + /// # Safety + /// + /// The caller must ensure the underlying memory is not aliased elsewhere. pub unsafe fn memset_with_deps( &mut self, array: &mut UsmBox, @@ -128,7 +145,7 @@ impl Queue { /// Submits a barrier to the queue. pub fn barrier(&mut self) -> Result { - self.barrier_with_deps(&[]).map(Into::into) + self.barrier_with_deps(&[]) } /// Submits a barrier to the queue after all specified events finish. @@ -153,7 +170,9 @@ impl Queue { /// Enqueues a kernel object to the queue as an ND-range kernel, using the number of work-items /// specified by the [`NdRange`] nd_range. /// - /// Safety: The caller must make sure each argument matches the launched SYCL kernel's + /// # Safety + /// + /// The caller must make sure each argument matches the launched SYCL kernel's /// signature, including their respective size, layout and alignment. pub unsafe fn launch( &mut self, diff --git a/sycl/sycl-rs/src/range.rs b/sycl/sycl-rs/src/range.rs index ca79b28..c8b4059 100644 --- a/sycl/sycl-rs/src/range.rs +++ b/sycl/sycl-rs/src/range.rs @@ -42,6 +42,10 @@ impl NdRange { /// [`NdRange`] types which are limited to 1, 2 or 3 dimensions. pub trait ValidDimension: Sealed { + /// # Safety + /// + /// Each argument must match the launched SYCL kernel's signature, including its size, + /// layout, and alignment. unsafe fn launch( &self, queue: &mut Queue, diff --git a/sycl/sycl-rs/src/usm.rs b/sycl/sycl-rs/src/usm.rs index a320d35..04f1e69 100644 --- a/sycl/sycl-rs/src/usm.rs +++ b/sycl/sycl-rs/src/usm.rs @@ -23,21 +23,28 @@ pub struct UsmAllocator { /// A marker trait for USM allocators. /// -/// Safety: a type implementing this trait must be a valid USM allocator managed by a SYCL runtime. +/// # Safety +/// +/// A type implementing this trait must be a valid USM allocator managed by a SYCL runtime. pub unsafe trait UsmAlloc: Allocator {} unsafe impl UsmAlloc for UsmAllocator {} pub trait UsmAllocatorKind { /// Allocates uninitialized memory. - /// Safety: the caller must not read uninitialized memory. The caller must also free this + /// + /// # Safety + /// + /// The caller must not read uninitialized memory. The caller must also free this /// memory manually. unsafe fn alloc(alignment: usize, num_bytes: usize, queue: &Queue) -> CxxResult<*mut u8>; } /// A marker trait for host-accessible USM allocators. /// -/// Safety: a type implementing this trait must be a valid USM allocator managed by a SYCL runtime, +/// # Safety +/// +/// A type implementing this trait must be a valid USM allocator managed by a SYCL runtime, /// that allocates memory accessible from the host. pub unsafe trait HostAccessible {} diff --git a/sycl/sycl-rs/src/usmbox.rs b/sycl/sycl-rs/src/usmbox.rs index 891e281..b9ba1ab 100644 --- a/sycl/sycl-rs/src/usmbox.rs +++ b/sycl/sycl-rs/src/usmbox.rs @@ -51,7 +51,7 @@ impl UsmBox { /// Safety: returns uninitialized memory. pub(crate) unsafe fn new(allocator: A, len: usize) -> Self { let layout = Layout::array::(len).unwrap(); - let ptr = match allocator.allocate(layout.clone()) { + let ptr = match allocator.allocate(layout) { Ok(ptr) => ptr, _ => handle_alloc_error(layout), };