Skip to content

Commit cf7c69e

Browse files
committed
fix: propagate implicit --target to fallback_clang_args
Fixes #3352 When bindgen infers the target triple from the Rust target (i.e., no explicit --target in clang_args), it inserts --target= into clang_args at Bindings::generate() time. However, fallback_clang_args was already populated from clang_args earlier in Builder::generate(), before this insertion. This meant the fallback translation unit used for clang_macro_fallback would use the host architecture instead of the target architecture. For cross-compilation, this caused sizeof-dependent macros (e.g., ioctl constants using _IOR/_IOW) to evaluate with the host's struct layouts instead of the target's, producing silently wrong values. Fix: when inserting the inferred target into clang_args, also insert it into fallback_clang_args.
1 parent d95d75a commit cf7c69e

File tree

2 files changed

+50
-4
lines changed

2 files changed

+50
-4
lines changed

bindgen-tests/tests/tests.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,52 @@ fn test_macro_fallback_header_contents_parent_dir_escape() {
824824
assert_eq!(fs::read_to_string(&victim).unwrap(), "// must survive\n",);
825825
}
826826

827+
#[test]
828+
fn test_macro_fallback_cross_target() {
829+
// Subprocess-style test: setting TARGET as an env var in a parallel
830+
// test is not robust, so we re-invoke the test binary as a child
831+
// process with TARGET set to a non-host triple. The child runs the
832+
// actual assertion; the parent just checks the exit status.
833+
//
834+
// __SIZEOF_POINTER__ is a clang builtin that equals the target's
835+
// pointer width. On armv7 it's 4; on x86_64 it's 8. If the
836+
// implicit --target isn't propagated to fallback_clang_args, the
837+
// fallback TU evaluates with the host pointer size instead.
838+
if env::var("__BINDGEN_CROSS_TARGET_INNER").is_ok() {
839+
let tmpdir = tempfile::tempdir().unwrap();
840+
let actual = builder()
841+
.disable_header_comment()
842+
.header_contents("test.h", "#define PTR_BYTES __SIZEOF_POINTER__\n")
843+
.clang_macro_fallback()
844+
.clang_macro_fallback_build_dir(tmpdir.path())
845+
.generate()
846+
.unwrap()
847+
.to_string();
848+
assert!(
849+
actual.contains("pub const PTR_BYTES: u32 = 4;"),
850+
"Expected 4-byte pointers for armv7 target, got:\n{actual}"
851+
);
852+
return;
853+
}
854+
855+
let exe = env::current_exe().unwrap();
856+
let output = std::process::Command::new(&exe)
857+
.arg("test_macro_fallback_cross_target")
858+
.arg("--exact")
859+
.arg("--test-threads=1")
860+
.env("TARGET", "armv7-unknown-linux-gnueabihf")
861+
.env("__BINDGEN_CROSS_TARGET_INNER", "1")
862+
.output()
863+
.unwrap();
864+
865+
let stdout = String::from_utf8_lossy(&output.stdout);
866+
let stderr = String::from_utf8_lossy(&output.stderr);
867+
assert!(
868+
output.status.success(),
869+
"Cross-target fallback test failed.\nstdout:\n{stdout}\nstderr:\n{stderr}"
870+
);
871+
}
872+
827873
#[test]
828874
// Doesn't support executing sh file on Windows.
829875
// We may want to implement it in Rust so that we support all systems.

bindgen/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,10 +787,10 @@ impl Bindings {
787787
// opening libclang.so, it has to be the same architecture and thus the
788788
// check is fine.
789789
if !explicit_target && !is_host_build {
790-
options.clang_args.insert(
791-
0,
792-
format!("--target={effective_target}").into_boxed_str(),
793-
);
790+
let target_arg =
791+
format!("--target={effective_target}").into_boxed_str();
792+
options.clang_args.insert(0, target_arg.clone());
793+
options.fallback_clang_args.insert(0, target_arg);
794794
}
795795

796796
fn detect_include_paths(options: &mut BindgenOptions) {

0 commit comments

Comments
 (0)