Skip to content

How to handle C array of undefined size? #2883

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mgeier opened this issue Aug 15, 2024 · 1 comment
Closed

How to handle C array of undefined size? #2883

mgeier opened this issue Aug 15, 2024 · 1 comment

Comments

@mgeier
Copy link

mgeier commented Aug 15, 2024

Input C/C++ Header

extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];

This is the declaration in the header file: https://github.com/xiph/flac/blob/28e4f0528c76b296c561e922ba67d43751990599/include/FLAC/format.h#L764-L771

And here's the definition (which I guess isn't visible to bindgen): https://github.com/xiph/flac/blob/28e4f0528c76b296c561e922ba67d43751990599/src/libFLAC/format.c#L185-L207

Bindgen Invocation

$ bindgen wrapper.h -o ../src/bindings.rs \
	--disable-name-namespacing \
	--no-doc-comments \
	--no-prepend-enum-name \
	--use-core \
	--ctypes-prefix libc \
	--allowlist-function "FLAC_.*" \
	--allowlist-type "FLAC_.*" \
	--allowlist-var "FLAC_.*" \
	--blocklist-type FILE \
	--blocklist-type "_IO_.*" \
	--

Actual Results

extern "C" {
    pub static FLAC__StreamMetadata_Picture_TypeString: [*const libc::c_char; 0usize];
}

I have used this in the past to access array elements:

    let ptr = unsafe { *FLAC__StreamMetadata_Picture_TypeString.get_unchecked(idx) };

But recently I've been getting this panic (in debug mode):

unsafe precondition(s) violated: slice::get_unchecked requires that the index is within the slice

This is understandable, since it is defined as zero-element array, but it has more than zero elements in the C library ...

I could work around this by using something like:

    let ptr = unsafe { *FLAC__StreamMetadata_Picture_TypeString.as_ptr().add(idx) };

But is this the right thing to do?

Expected Results

I don't know!

Maybe something has to be changed in the original C definitions?

I'd be grateful for any hints!

@pvdrz
Copy link
Contributor

pvdrz commented Aug 15, 2024

I wouldn't suggest modifying the C definition as it seems this array is supposed to be indexed by values of the FLAC__StreamMetadata_Picture_Type enum and those values could easily change in the future, right now they go up to 20 so you could argue that this should be an array of 20 elements but I wouldn't set that in stone.

I would argue that having zero sized arrays as the default representation of unsized C arrays is not the most correct thing and maybe bindgen should translate them as pointers instead. But for the meantime, I think your solution is correct. You could wrap such logic in a function to avoid issues in the future

fn get_picture_type_string(idx: FLAC__StreamMetadata_Picture_Type) -> Option<const* c_char> {
    if idx == FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED {
        None
    } else {
        Some(unsafe { *FLAC__StreamMetadata_Picture_TypeString.as_ptr().add(idx) })
    }
}

EDIT: it seems these arrays are treated as zero-sized arrays because that was the only way to make them work, see: #683. But yes, accessing the array by using the raw pointer is fine.

@pvdrz pvdrz closed this as completed Aug 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants