authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-09 00:03:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-09 00:07:02-07:00
logc7d6048081053c2852d4d3af5d549d83473f808c
tree8211b4014b632b53673d7d48fca5663d1890156e
parent9f40f34501ef086d18e4570416c078a7ad508628

std.zig.system.NativeTargetInfo: add fallback check

After failing to find RUNPATH in the ELF of /usr/bin/env, not finding the answer in a symlink of the dynamic interpreter, and not finding libc.so.6 in the same directory as the dynamic interpreter, Zig will check `/lib/$triple`. This fixes incorrect native glibc version detected on Debian bookworm.

1 files changed, 74 insertions(+), 42 deletions(-)

lib/std/zig/system/NativeTargetInfo.zig+74-42
......@@ -820,55 +820,87 @@ pub fn abiAndDynamicLinkerFromFile(
820820 while (it.next()) |rpath| {
821821 if (glibcVerFromRPath(rpath)) |ver| {
822822 result.target.os.version_range.linux.glibc = ver;
823 break;
823 return result;
824824 } else |err| switch (err) {
825825 error.GLibCNotFound => continue,
826826 else => |e| return e,
827827 }
828828 }
829 } else if (result.dynamic_linker.get()) |dl_path| glibc_ver: {
830 // There is no DT_RUNPATH so we try to find libc.so.6 inside the same
831 // directory as the dynamic linker.
832 if (fs.path.dirname(dl_path)) |rpath| {
833 if (glibcVerFromRPath(rpath)) |ver| {
834 result.target.os.version_range.linux.glibc = ver;
835 break :glibc_ver;
836 } else |err| switch (err) {
837 error.GLibCNotFound => {},
838 else => |e| return e,
839 }
840 }
829 }
830 }
841831
842 // So far, no luck. Next we try to see if the information is
843 // present in the symlink data for the dynamic linker path.
844 var link_buf: [std.os.PATH_MAX]u8 = undefined;
845 const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) {
846 error.NameTooLong => unreachable,
847 error.InvalidUtf8 => unreachable, // Windows only
848 error.BadPathName => unreachable, // Windows only
849 error.UnsupportedReparsePointType => unreachable, // Windows only
850
851 error.AccessDenied,
852 error.FileNotFound,
853 error.NotLink,
854 error.NotDir,
855 => break :glibc_ver,
856
857 error.SystemResources,
858 error.FileSystem,
859 error.SymLinkLoop,
860 error.Unexpected,
861 => |e| return e,
862 };
863 result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
864 fs.path.basename(link_name),
865 "ld-",
866 ) catch |err| switch (err) {
867 error.UnrecognizedGnuLibCFileName,
868 error.InvalidGnuLibCVersion,
869 => break :glibc_ver,
870 };
832 if (result.dynamic_linker.get()) |dl_path| glibc_ver: {
833 // There is no DT_RUNPATH so we try to find libc.so.6 inside the same
834 // directory as the dynamic linker.
835 if (fs.path.dirname(dl_path)) |rpath| {
836 if (glibcVerFromRPath(rpath)) |ver| {
837 result.target.os.version_range.linux.glibc = ver;
838 return result;
839 } else |err| switch (err) {
840 error.GLibCNotFound => {},
841 else => |e| return e,
842 }
871843 }
844
845 // So far, no luck. Next we try to see if the information is
846 // present in the symlink data for the dynamic linker path.
847 var link_buf: [std.os.PATH_MAX]u8 = undefined;
848 const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) {
849 error.NameTooLong => unreachable,
850 error.InvalidUtf8 => unreachable, // Windows only
851 error.BadPathName => unreachable, // Windows only
852 error.UnsupportedReparsePointType => unreachable, // Windows only
853
854 error.AccessDenied,
855 error.FileNotFound,
856 error.NotLink,
857 error.NotDir,
858 => break :glibc_ver,
859
860 error.SystemResources,
861 error.FileSystem,
862 error.SymLinkLoop,
863 error.Unexpected,
864 => |e| return e,
865 };
866 result.target.os.version_range.linux.glibc = glibcVerFromLinkName(
867 fs.path.basename(link_name),
868 "ld-",
869 ) catch |err| switch (err) {
870 error.UnrecognizedGnuLibCFileName,
871 error.InvalidGnuLibCVersion,
872 => break :glibc_ver,
873 };
874 return result;
875 }
876
877 // Nothing worked so far. Finally we fall back to hard-coded search paths.
878 // Some distros such as Debian keep their libc.so.6 in `/lib/$triple/`.
879 var path_buf: [std.os.PATH_MAX]u8 = undefined;
880 var index: usize = 0;
881 const prefix = "/lib/";
882 const cpu_arch = @tagName(result.target.cpu.arch);
883 const os_tag = @tagName(result.target.os.tag);
884 const abi = @tagName(result.target.abi);
885 mem.copy(u8, path_buf[index..], prefix);
886 index += prefix.len;
887 mem.copy(u8, path_buf[index..], cpu_arch);
888 index += cpu_arch.len;
889 path_buf[index] = '-';
890 index += 1;
891 mem.copy(u8, path_buf[index..], os_tag);
892 index += os_tag.len;
893 path_buf[index] = '-';
894 index += 1;
895 mem.copy(u8, path_buf[index..], abi);
896 index += abi.len;
897 const rpath = path_buf[0..index];
898 if (glibcVerFromRPath(rpath)) |ver| {
899 result.target.os.version_range.linux.glibc = ver;
900 return result;
901 } else |err| switch (err) {
902 error.GLibCNotFound => {},
903 else => |e| return e,
872904 }
873905 }
874906