From c1285b4fe661798fcc618bdd55a83b0172142f18 Mon Sep 17 00:00:00 2001 From: David Lattimore Date: Thu, 31 Oct 2024 21:51:27 +1100 Subject: [PATCH] Add a test to verify that libstd doesn't use protected symbols --- tests/run-make/libstd-no-protected/rmake.rs | 63 +++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 tests/run-make/libstd-no-protected/rmake.rs diff --git a/tests/run-make/libstd-no-protected/rmake.rs b/tests/run-make/libstd-no-protected/rmake.rs new file mode 100644 index 0000000000000..3bba59a8f4d55 --- /dev/null +++ b/tests/run-make/libstd-no-protected/rmake.rs @@ -0,0 +1,63 @@ +// If libstd was compiled to use protected symbols, then linking would fail if GNU ld < 2.40 were +// used. This might not be noticed, since usually we use LLD for linking, so we could end up +// distributing a version of libstd that would cause link errors for such users. + +//@ only-x86_64-unknown-linux-gnu + +use run_make_support::object::Endianness; +use run_make_support::object::read::archive::ArchiveFile; +use run_make_support::object::read::elf::{FileHeader as _, SectionHeader as _}; +use run_make_support::rfs::{read, read_dir}; +use run_make_support::{has_prefix, has_suffix, object, path, rustc, shallow_find_files, target}; + +type FileHeader = run_make_support::object::elf::FileHeader64; +type SymbolTable<'data> = run_make_support::object::read::elf::SymbolTable<'data, FileHeader>; + +fn main() { + // Find libstd-...rlib + let sysroot = rustc().print("sysroot").run().stdout_utf8(); + let sysroot = sysroot.trim(); + let target_sysroot = path(sysroot).join("lib/rustlib").join(target()).join("lib"); + let mut libs = shallow_find_files(&target_sysroot, |path| { + has_prefix(path, "libstd-") && has_suffix(path, ".rlib") + }); + assert_eq!(libs.len(), 1); + let libstd_path = libs.pop().unwrap(); + let archive_data = read(libstd_path); + + // Parse all the object files within the libstd archive, checking defined symbols. + let mut num_protected = 0; + let mut num_symbols = 0; + + let archive = ArchiveFile::parse(&*archive_data).unwrap(); + for member in archive.members() { + let member = member.unwrap(); + if member.name() == b"lib.rmeta" { + continue; + } + let data = member.data(&*archive_data).unwrap(); + + let header = FileHeader::parse(data).unwrap(); + let endian = header.endian().unwrap(); + let sections = header.sections(endian, data).unwrap(); + + for (section_index, section) in sections.enumerate() { + if section.sh_type(endian) == object::elf::SHT_SYMTAB { + let symbols = + SymbolTable::parse(endian, data, §ions, section_index, section).unwrap(); + for symbol in symbols.symbols() { + if symbol.st_visibility() == object::elf::STV_PROTECTED { + num_protected += 1; + } + num_symbols += 1; + } + } + } + } + + // If there were no symbols at all, then something is wrong with the test. + assert_ne!(num_symbols, 0); + + // The purpose of this test - check that no symbols have protected visibility. + assert_eq!(num_protected, 0); +}