rust-lang / rust-lang/rust-bindgen

--wrap-static-fns generates invalid C for pointer-to-array parameters and returns

Open
#3,403 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

Input C/C++ Header
static inline int (*phase8_array_identity(int (*value)[4]))[4] {
    return value;
}
Bindgen Invocation
$ bindgen input.h \
    --wrap-static-fns \
    --wrap-static-fns-path wrapper \
    --rust-target 1.75 \
    --no-layout-tests \
    --no-rustfmt-bindings \
    --output bindings.rs
Actual Results

The Rust declaration has the expected pointer-to-array type:

extern "C" {
    #[link_name = "phase8_array_identity__extern"]
    pub fn phase8_array_identity(
        value: *mut [::std::os::raw::c_int; 4usize],
    ) -> *mut [::std::os::raw::c_int; 4usize];
}

The generated wrapper.c does not preserve the C declarator:

int * [4] phase8_array_identity__extern(int *value [4]) {
    return phase8_array_identity(value);
}

Clang rejects it:

error: brackets are not allowed here
error: function cannot return array type 'int *[4]'
error: incompatible pointer types passing 'int **' to parameter of type 'int (*)[4]'

The parameter is wrong as well as the return type. In a parameter list,
int *value[4] is adjusted to int **; it is not int (*)[4].

Expected Results

The generated wrapper needs parentheses around the pointer declarators:

int (*phase8_array_identity__extern(int (*value)[4]))[4] {
    return phase8_array_identity(value);
}

I compiled that wrapper and linked it to a Rust caller using the generated
bindings.rs without edits. The direct C caller and the Rust caller both
printed:

identity=1 sum=10 first=1 last=4
Environment
bindgen current main: 9d26c6eddeff9192ddedb563192abe3128fc5aae
bindgen release:      0.72.1
clang:                15.0.7
rustc:                1.75.0
target:               x86_64-unknown-linux-gnu

The same generated C compile failure occurs with current main and 0.72.1,
at both O0 and O2.

Additional notes

This looks like a declarator serialization problem. The array serializer
appends [length], while the pointer serializer pushes * onto the type
string. That is not enough to represent cases where the * must be
parenthesized.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the bindgen invocation from the issue and inspect wrapper.c alongside bindings.rs, focusing on the array and pointer declarator serializers described in the report. Done means the wrapper preserves parentheses for pointer-to-array parameters and returns, compiles with Clang, and the direct C and Rust callers produce identity=1 sum=10 first=1 last=4.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, rust
Domain
compilers, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.