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(...@@ -820,55 +820,87 @@ pub fn abiAndDynamicLinkerFromFile(
820 while (it.next()) |rpath| {820 while (it.next()) |rpath| {
821 if (glibcVerFromRPath(rpath)) |ver| {821 if (glibcVerFromRPath(rpath)) |ver| {
822 result.target.os.version_range.linux.glibc = ver;822 result.target.os.version_range.linux.glibc = ver;
823 break;823 return result;
824 } else |err| switch (err) {824 } else |err| switch (err) {
825 error.GLibCNotFound => continue,825 error.GLibCNotFound => continue,
826 else => |e| return e,826 else => |e| return e,
827 }827 }
828 }828 }
829 } else if (result.dynamic_linker.get()) |dl_path| glibc_ver: {829 }
830 // There is no DT_RUNPATH so we try to find libc.so.6 inside the same830 }
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 }
841831
842 // So far, no luck. Next we try to see if the information is832 if (result.dynamic_linker.get()) |dl_path| glibc_ver: {
843 // present in the symlink data for the dynamic linker path.833 // There is no DT_RUNPATH so we try to find libc.so.6 inside the same
844 var link_buf: [std.os.PATH_MAX]u8 = undefined;834 // directory as the dynamic linker.
845 const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) {835 if (fs.path.dirname(dl_path)) |rpath| {
846 error.NameTooLong => unreachable,836 if (glibcVerFromRPath(rpath)) |ver| {
847 error.InvalidUtf8 => unreachable, // Windows only837 result.target.os.version_range.linux.glibc = ver;
848 error.BadPathName => unreachable, // Windows only838 return result;
849 error.UnsupportedReparsePointType => unreachable, // Windows only839 } else |err| switch (err) {
850840 error.GLibCNotFound => {},
851 error.AccessDenied,841 else => |e| return e,
852 error.FileNotFound,842 }
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 };
871 }843 }
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,
872 }904 }
873 }905 }
874906