diff --git a/src/gallium/frontends/rusticl/api/program.rs b/src/gallium/frontends/rusticl/api/program.rs index e2a1776fcbe..7f1fb335d71 100644 --- a/src/gallium/frontends/rusticl/api/program.rs +++ b/src/gallium/frontends/rusticl/api/program.rs @@ -477,18 +477,12 @@ pub fn link_program( return Err(CL_INVALID_OPERATION); } - let (res, code) = Program::link( - context, - devices, - input_programs, - c_string_to_string(options), - callback, - )?; + // SAFETY: options is a valid C String or NULL. + let options = unsafe { CStr::from_ptr_or_empty(&options) }; + + let (res, code) = Program::link(context, devices, input_programs, options, callback)?; Ok((res.into_cl(), code)) - - //• CL_INVALID_LINKER_OPTIONS if the linker options specified by options are invalid. - //• CL_INVALID_OPERATION if the rules for devices containing compiled binaries or libraries as described in input_programs argument above are not followed. } #[cl_entrypoint(clSetProgramSpecializationConstant)] diff --git a/src/gallium/frontends/rusticl/core/program.rs b/src/gallium/frontends/rusticl/core/program.rs index 83bc9794490..043566ca7c3 100644 --- a/src/gallium/frontends/rusticl/core/program.rs +++ b/src/gallium/frontends/rusticl/core/program.rs @@ -425,6 +425,43 @@ impl CompileOptions { } } +/// Parsed and validated link options. +struct LinkOptions { + create_lib: bool, +} + +impl LinkOptions { + /// Parses and validates link options according to the OpenCL 3.0 specification + /// (Section 5.8.7). Returns CL_INVALID_LINKER_OPTIONS if any option is invalid. + fn new(options: &CStr) -> CLResult { + let mut create_lib = false; + + if options.is_empty() { + return Ok(Self { create_lib }); + } + + let options = options.to_str().map_err(|_| CL_INVALID_LINKER_OPTIONS)?; + + for token in options.split_whitespace() { + match token { + "-create-library" => { + create_lib = true; + } + "-enable-link-options" + | "-cl-denorms-are-zero" + | "-cl-no-signed-zeros" + | "-cl-unsafe-math-optimizations" + | "-cl-finite-math-only" + | "-cl-fast-relaxed-math" + | "-cl-no-subgroup-ifp" => {} + _ => return Err(CL_INVALID_LINKER_OPTIONS), + } + } + + Ok(Self { create_lib }) + } +} + impl Program { fn create_default_builds( devs: &[&'static Device], @@ -847,9 +884,13 @@ impl Program { context: Arc, devices: Vec<&'static Device>, input_programs: Vec>, - options: String, + options: &CStr, callback: Option, ) -> CLResult<(Arc, cl_int)> { + // Validate options before starting the link. + // clLinkProgram must return CL_INVALID_LINKER_OPTIONS if options are invalid. + let options = LinkOptions::new(options)?; + // Link can begin, so we must return a valid program object. let builds_by_device = devices .iter() @@ -1120,12 +1161,12 @@ fn create_link_closure( program: Arc, devices: Vec<&'static Device>, input_programs: Vec>, - options: String, + options: LinkOptions, mut callback: Option, ) -> impl FnMut() + Send + Sync + 'static { move || { let mut locks: Vec<_> = input_programs.iter().map(|p| p.build_info()).collect(); - let is_lib = options.contains("-create-library"); + let is_lib = options.create_lib; let mut build_info = program.build_info();