Skip to content

Can't use fn() for C binding if C uses sentinel value #141660

Open
@karolherbst

Description

@karolherbst

I've tried to implement the cl_khr_icd 2.0.0 OpenCL extension in Rust. This extension requires the implementers to set constant values to certain function pointers. rustc told me to file an issue, so here I am.

I don't know how widespread this kind of pattern is, and if it could become a problem implementing other C APIs in Rust.

As a side note, constructing the same value at runtime instead of at compile time makes the code compile. Obviously actually calling the function will be undefined behavior. The constant value just is just a marker to loaders to advertise that version 2.0.0 of cl_khr_icd is supported. It is not expected to be called at all by anything.

Below is a simplified version of the code:

#![allow(non_camel_case_types, non_snake_case)]

use std::mem;

pub type cl_int = i32;
pub type cl_uint = u32;
pub type cl_platform_id = *mut _cl_platform_id;
pub type cl_icd_dispatch = _cl_icd_dispatch;

pub struct _cl_platform_id {
    pub dispatch: *const cl_icd_dispatch,
}

pub type clGetPlatformIDs_t = ::std::option::Option<
    unsafe extern "C" fn(
        num_entries: cl_uint,
        platforms: *mut cl_platform_id,
        num_platforms: *mut cl_uint,
    ) -> cl_int,
>;

pub struct _cl_icd_dispatch {
    pub clGetPlatformIDs: clGetPlatformIDs_t,
}

#[cfg(target_pointer_width = "32")]
const CL_ICD2_TAG_KHR: usize = 0x434C3331;

#[cfg(target_pointer_width = "64")]
const CL_ICD2_TAG_KHR: usize = 0x4F50454E434C3331;

pub static DISPATCH: cl_icd_dispatch = cl_icd_dispatch {
    clGetPlatformIDs: unsafe { mem::transmute_copy(&CL_ICD2_TAG_KHR) },
};

I expected to see this happen: It should compile and place the constant values in the static data.

Instead, this happened:

error[E0080]: it is undefined behavior to use this value
  --> test.rs:32:1
   |
32 | pub static DISPATCH: cl_icd_dispatch = cl_icd_dispatch {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .clGetPlatformIDs.<enum-variant(Some)>.0: encountered 0x4f50454e434c3331[noalloc], but expected a function pointer
   |
   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
   = note: the raw bytes of the constant (size: 8, align: 8) {
               31 33 4c 43 4e 45 50 4f                         │ 13LCNEPO
           }

Meta

rustc --version --verbose:

rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: x86_64-unknown-linux-gnu
release: 1.85.0
LLVM version: 19.1.7

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-FFIArea: Foreign function interface (FFI)C-discussionCategory: Discussion or questions that doesn't represent real issues.T-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions