rust-lang / rust-lang/rust-bindgen
`__attribute__((weak))` declarations are emitted as ordinary externs, producing strong undefined references on ELF
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
int api_version(void);
int optional_api(int value) __attribute__((weak));
The first declaration makes sure the test still depends on the shared library
when optional_api is missing. The weak function is used in the usual way:
return optional_api ? optional_api(value) : value + 100;
Bindgen Invocation
$ bindgen weak_api.h \
--rust-target 1.75 \
--no-layout-tests \
--no-rustfmt-bindings \
--output bindings.rs \
-- -I.
Actual Results
The relevant output, reformatted for readability, is:
extern "C" {
pub fn api_version() -> ::std::os::raw::c_int;
}
extern "C" {
pub fn optional_api(
value: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int;
}
optional_api is represented like an ordinary required function. With bindgen
0.72.1 and rustc 1.75, the C and Rust callers lower to:
; C
declare extern_weak i32 @optional_api(i32 noundef)
; Rust, using bindings.rs unchanged
declare noundef i32 @optional_api(i32 noundef) unnamed_addr
A source build from current main at
9d26c6eddeff9192ddedb563192abe3128fc5aae produced the same ordinary Rust
declaration. In that run, the ELF symbol tables contain:
C caller: WEAK UND optional_api
Rust caller: GLOBAL UND optional_api
The full reproducer is
weak-function-linkage-repro.zip.
It builds an old library that exports only api_version, and a new library
that also exports optional_api:
$ unzip weak-function-linkage-repro.zip
$ cd repro
$ BINDGEN=/path/to/bindgen ./run.sh
Both the 0.72.1 and current-main runs gave these results:
C linked to old: version=1 fallback=105
C linked to new: version=2 optional=205
Rust linked to new: version=2 optional=205
Rust linked directly to old: link error, undefined reference to optional_api
C linked to new, run with old: version=1 fallback=105
Rust linked to new, run with old: exit 127, undefined symbol: optional_api
The C caller can run with the old library and take its fallback path. The Rust
caller using the unchanged generated declaration either fails to link or fails
during loader symbol resolution.
As a header-level example, JACK marks APIs such as
jack_set_latency_callback with JACK_WEAK_EXPORT so a caller can check
whether the function exists when using an older JACK library. Bindgen emits
that declaration as an ordinary extern function too.
--dynamic-loading WeakApi is a separate opt-in libloading workaround.
Without --dynamic-link-require-all, both api_version and optional_api
become fallible lookups. It does not preserve the default linker behavior or
infer optionality from the weak attribute.
$ bindgen --version
bindgen 0.72.1
$ clang --version
Ubuntu clang version 15.0.7
$ rustc --version
rustc 1.75.0
Release target: x86_64-unknown-linux-gnu.
The current-main run used rustc 1.82.0. Its bindgen CLI reported 0.72.0, so the
commit above identifies that build.
Expected Results
A binding that keeps optional_api optional, or an explicit diagnostic if the
selected output mode cannot preserve weak imports.
I am not prescribing a particular Rust representation. Silently emitting an
ordinary extern function changes the weak declaration into a required symbol
on ELF.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the weak_api.h reproducer and run.sh, then inspect the generated bindings.rs and the ELF symbol results described in the issue. Trace how bindgen handles attribute((weak)) declarations and compare the Rust output with the C caller. Done means weak imports remain optional, or bindgen reports that the selected output mode cannot preserve them.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cpp, rust
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100