Skip to content

Commit

Permalink
rust: warn about bindgen versions 0.66.0 and 0.66.1
Browse files Browse the repository at this point in the history
`bindgen` versions 0.66.0 and 0.66.1 panic due to C string literals with
NUL characters [1]:

    panicked at .cargo/registry/src/index.crates.io-6f17d22bba15001f/bindgen-0.66.0/codegen/mod.rs:717:71:
    called `Result::unwrap()` on an `Err` value: FromBytesWithNulError { kind: InteriorNul(4) }

Thus, in preparation for supporting several `bindgen` versions, add a
version check to warn the user about it.

Since some distributions may have patched it (e.g. Debian did [2]),
check if that seems to be the case (after the version check matches),
in order to avoid printing a warning in that case.

We could make it an error, but 1) it is going to fail anyway later
in the build, 2) we would disable `RUST`, which is also painful, 3)
someone could have patched it in a way that still makes our extra check
fail (however unlikely), 4) the interior NUL may go away in the headers
(however unlikely). Thus just warn about it so that users know why it
is failing.

In addition, add a couple tests for the new cases.

Link: rust-lang/rust-bindgen#2567 [1]
Link: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1069047 [2]
Link: https://lore.kernel.org/r/20240709160615.998336-11-ojeda@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
  • Loading branch information
ojeda authored and herrnst committed Sep 4, 2024
1 parent 8d9b5f8 commit a1a0cb1
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 3 deletions.
13 changes: 13 additions & 0 deletions scripts/rust_is_available.sh
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,19 @@ if [ "$rust_bindings_generator_cversion" -lt "$rust_bindings_generator_min_cvers
echo >&2 "***"
exit 1
fi
if [ "$rust_bindings_generator_cversion" -eq 6600 ] ||
[ "$rust_bindings_generator_cversion" -eq 6601 ]; then
# Distributions may have patched the issue (e.g. Debian did).
if ! "$BINDGEN" $(dirname $0)/rust_is_available_bindgen_0_66.h >/dev/null; then
echo >&2 "***"
echo >&2 "*** Rust bindings generator '$BINDGEN' versions 0.66.0 and 0.66.1 may not"
echo >&2 "*** work due to a bug (https://github.com/rust-lang/rust-bindgen/pull/2567),"
echo >&2 "*** unless patched (like Debian's)."
echo >&2 "*** Your version: $rust_bindings_generator_version"
echo >&2 "***"
warning=1
fi
fi

# Check that the `libclang` used by the Rust bindings generator is suitable.
#
Expand Down
2 changes: 2 additions & 0 deletions scripts/rust_is_available_bindgen_0_66.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/* SPDX-License-Identifier: GPL-2.0 */
#define A "\0"
26 changes: 23 additions & 3 deletions scripts/rust_is_available_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,23 +54,30 @@ def generate_rustc(cls, stdout):
""")

@classmethod
def generate_bindgen(cls, version_stdout, libclang_stderr):
def generate_bindgen(cls, version_stdout, libclang_stderr, version_0_66_patched=False):
if libclang_stderr is None:
libclang_case = f"raise SystemExit({cls.bindgen_default_bindgen_libclang_failure_exit_code})"
else:
libclang_case = f"print({repr(libclang_stderr)}, file=sys.stderr)"

if version_0_66_patched:
version_0_66_case = "pass"
else:
version_0_66_case = "raise SystemExit(1)"

return cls.generate_executable(f"""#!/usr/bin/env python3
import sys
if "rust_is_available_bindgen_libclang.h" in " ".join(sys.argv):
{libclang_case}
elif "rust_is_available_bindgen_0_66.h" in " ".join(sys.argv):
{version_0_66_case}
else:
print({repr(version_stdout)})
""")

@classmethod
def generate_bindgen_version(cls, stdout):
return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr)
def generate_bindgen_version(cls, stdout, version_0_66_patched=False):
return cls.generate_bindgen(stdout, cls.bindgen_default_bindgen_libclang_stderr, version_0_66_patched)

@classmethod
def generate_bindgen_libclang_failure(cls):
Expand Down Expand Up @@ -231,6 +238,19 @@ def test_bindgen_old_version(self):
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' is too old.", result.stderr)

def test_bindgen_bad_version_0_66_0_and_0_66_1(self):
for version in ("0.66.0", "0.66.1"):
with self.subTest(version=version):
bindgen = self.generate_bindgen_version(f"bindgen {version}")
result = self.run_script(self.Expected.SUCCESS_WITH_WARNINGS, { "BINDGEN": bindgen })
self.assertIn(f"Rust bindings generator '{bindgen}' versions 0.66.0 and 0.66.1 may not", result.stderr)

def test_bindgen_bad_version_0_66_0_and_0_66_1_patched(self):
for version in ("0.66.0", "0.66.1"):
with self.subTest(version=version):
bindgen = self.generate_bindgen_version(f"bindgen {version}", True)
result = self.run_script(self.Expected.SUCCESS, { "BINDGEN": bindgen })

def test_bindgen_libclang_failure(self):
bindgen = self.generate_bindgen_libclang_failure()
result = self.run_script(self.Expected.FAILURE, { "BINDGEN": bindgen })
Expand Down

0 comments on commit a1a0cb1

Please sign in to comment.