zig
zig copied to clipboard
zig detects wrong libc version
My system libc version is 2.30
but zig detects and builds 2.17
which causes linking errors with expat
for example:
const std = @import("std");
const c = @cImport({
@cInclude("expat.h");
});
pub fn main() void {
std.debug.print("Take off every Zig\n", .{});
}
zig-git build-exe -lc -lexpat test.zig --verbose-link
lld -error-limit=0 -z stack-size=16777216 --gc-sections -m elf_x86_64 -o test /home/ifreund/.cache/zig/o/e078967572054b1e20fb7e32da06f238/Scrt1.o /home/ifreund/.cache/zig/o/9a9a917500aa09fcd6cbafb708b1d6e3/crti.o -L /usr/local/lib64 -L /usr/local/lib -L /usr/lib/x86_64-linux-gnu -L /lib64 -L /lib -L /usr/lib64 -L /usr/lib -L /lib/x86_64-linux-gnu -dynamic-linker /lib/ld-linux-x86-64.so.2 zig-cache/o/d6ab4d674788932c736c310c43b963b3/test.o /home/ifreund/.cache/zig/o/cac0c8a5e22159f852a543a37241f19a/libcompiler_rt.a -lexpat /home/ifreund/.cache/zig/o/ef893c3d724376328171551dc3f416d7/libunwind.a /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libc.so.6 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libm.so.6 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libpthread.so.0 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libdl.so.2 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/librt.so.1 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libld.so.2 /home/ifreund/.cache/zig/o/513bf1524998e06b2a99a61649abfd7d/libutil.so.1 /home/ifreund/.cache/zig/o/66a177e6febdd316bcf2348b13964c28/libc_nonshared.a /home/ifreund/.cache/zig/o/5d923f6790009188502400b46c05b3cf/crtn.o
lld: error: /lib64/libexpat.so: undefined reference to getrandom
error: LLDReportedFailure
Compiling with --show-builtin
gives the following os struct, demonstrating that the wrong glibc version is detected.
pub const os = Os{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 3,
.minor = 16,
.patch = 0,
},
.max = .{
.major = 5,
.minor = 5,
.patch = 5,
},
},
.glibc = .{
.major = 2,
.minor = 17,
.patch = 0,
},
}},
};
I am also running void linux, but Zig does detect the right version:
pub const os = Os{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 3,
.minor = 16,
.patch = 0,
},
.max = .{
.major = 5,
.minor = 5,
.patch = 5,
},
},
.glibc = .{
.major = 2,
.minor = 30,
.patch = 0,
},
}},
};
@ifreund can you double check with valgrind
that zig is not doing anything fishy?
Excuses, i hadn't built the most recent Zig compiler. It now also detects 2.17 on my system, so this seems to be a regression.
@ifreund can you double check with
valgrind
that zig is not doing anything fishy?
valgrind log
valgrind --leak-check=full zig-git build-exe -lc -lexpat test.zig
==19445== Memcheck, a memory error detector
==19445== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19445== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==19445== Command: zig-git build-exe -lc -lexpat test.zig
==19445==
lld: error: /lib64/libexpat.so: undefined reference to getrandom
error: LLDReportedFailure
==19445==
==19445== HEAP SUMMARY:
==19445== in use at exit: 200,937 bytes in 1,971 blocks
==19445== total heap usage: 7,099 allocs, 5,128 frees, 4,419,028 bytes allocated
==19445==
==19445== 59 bytes in 1 blocks are definitely lost in loss record 1,707 of 1,968
==19445== at 0x48B777F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19445== by 0x8D3434: std.heap.cAlloc (heap.zig:47)
==19445== by 0x96B516: std.mem.Allocator.allocAdvancedWithRetAddr.363 (Allocator.zig:294)
==19445== by 0x96B2BA: std.mem.Allocator.alloc.362 (Allocator.zig:186)
==19445== by 0x96BD85: std.fs.path.joinSep (path.zig:58)
==19445== by 0x8D3714: std.fs.path.joinPosix (path.zig:93)
==19445== by 0x9F1968: glibc.buildSharedObjects (glibc.zig:888)
==19445== by 0x9BE5A8: Compilation.performAllTheWork (Compilation.zig:1247)
==19445== by 0x9B8EE6: Compilation.update (Compilation.zig:1028)
==19445== by 0x95F596: main.updateModule (main.zig:1761)
==19445== by 0x8FC452: main.buildOutputType (main.zig:1637)
==19445== by 0x8D6189: main.mainArgs (main.zig:126)
==19445==
==19445== 192 bytes in 1 blocks are definitely lost in loss record 1,957 of 1,968
==19445== at 0x48B777F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19445== by 0x8D3434: std.heap.cAlloc (heap.zig:47)
==19445== by 0xBD2986: std.mem.Allocator.allocAdvancedWithRetAddr.3436 (Allocator.zig:294)
==19445== by 0xAAEDC6: std.mem.Allocator.allocAdvancedWithRetAddr.1806 (Allocator.zig:277)
==19445== by 0x994E6D: std.mem.Allocator.reallocAdvancedWithRetAddr.617 (Allocator.zig:375)
==19445== by 0x994D68: std.mem.Allocator.reallocAtLeast.616 (Allocator.zig:348)
==19445== by 0x9946FA: std.array_list.ArrayListAlignedUnmanaged(std.array_hash_map.Entry,null).ensureCapacity (array_list.zig:546)
==19445== by 0x98A68D: std.array_hash_map.ArrayHashMapUnmanaged([]const u8,void,std.array_hash_map.hashString,std.array_hash_map.eqlString,true).ensureCapacity (array_hash_map.zig:404)
==19445== by 0x95A241: Compilation.create (Compilation.zig:735)
==19445== by 0x8FB7EA: main.buildOutputType (main.zig:1533)
==19445== by 0x8D6189: main.mainArgs (main.zig:126)
==19445== by 0x8D5E6A: main (stage1.zig:42)
==19445==
==19445== 67,584 bytes in 1 blocks are definitely lost in loss record 1,968 of 1,968
==19445== at 0x48B777F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==19445== by 0x534E983: ??? (in /usr/lib/libLLVM-10.so)
==19445== by 0x534F27E: llvm::sys::RemoveFileOnSignal(llvm::StringRef, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*) (in /usr/lib/libLLVM-10.so)
==19445== by 0x53479AD: llvm::sys::fs::TempFile::create(llvm::Twine const&, unsigned int) (in /usr/lib/libLLVM-10.so)
==19445== by 0x529B8E5: llvm::FileOutputBuffer::create(llvm::StringRef, unsigned long, unsigned int) (in /usr/lib/libLLVM-10.so)
==19445== by 0x3778C8D: lld::tryCreateFile(llvm::StringRef) (in /home/ifreund/projects/zig/build/zig)
==19445== by 0x3436416: void lld::elf::LinkerDriver::link<llvm::object::ELFType<(llvm::support::endianness)1, true> >(llvm::opt::InputArgList&) (in /home/ifreund/projects/zig/build/zig)
==19445== by 0x8CE842: lld::elf::LinkerDriver::main(llvm::ArrayRef<char const*>) (in /home/ifreund/projects/zig/build/zig)
==19445== by 0x343ADAA: lld::elf::link(llvm::ArrayRef<char const*>, bool, llvm::raw_ostream&, llvm::raw_ostream&) (in /home/ifreund/projects/zig/build/zig)
==19445== by 0x13357A7: ZigLLDLink (zig_llvm.cpp:1064)
==19445== by 0xA145AC: link.Elf.linkWithLLD (Elf.zig:1608)
==19445== by 0xA03573: link.Elf.flush (Elf.zig:719)
==19445==
==19445== LEAK SUMMARY:
==19445== definitely lost: 67,835 bytes in 3 blocks
==19445== indirectly lost: 0 bytes in 0 blocks
==19445== possibly lost: 0 bytes in 0 blocks
==19445== still reachable: 133,102 bytes in 1,968 blocks
==19445== suppressed: 0 bytes in 0 blocks
==19445== Reachable blocks (those to which a pointer was found) are not shown.
==19445== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==19445==
==19445== For lists of detected and suppressed errors, rerun with: -s
==19445== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
Two problems here, the first being that getSelfExeSharedLibPaths
returns an empty array because builtin.link_mode==static
, even though the final zig
binary is not static. The second is trickier as /usr/bin/env
has no DT_RUNPATH
on my system (Debian 10 Buster), so even the second detection method fails.
Does the latter problem mean Zig should search the other places like DT_RPATH, LD_LIBRARY_PATH, /lib and /usr/lib similar to ld?
Regarding the builtin.link_mode
, when building some .zig file and adding -dynamic
to the command, the builtin.link_mode
changes to .Dynamic
. Thus this is actually not the link_mode
of the zig executable, but rather of the one that we are building currently.
--- a/src/stage1/codegen.cpp
+++ b/src/stage1/codegen.cpp
@@ -8815,7 +8815,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
buf_append_str(contents, "/// Deprecated: use `std.Target.current.cpu.arch.endian()`\n");
buf_append_str(contents, "pub const endian = Target.current.cpu.arch.endian();\n");
buf_appendf(contents, "pub const output_mode = OutputMode.Obj;\n");
- buf_appendf(contents, "pub const link_mode = LinkMode.Static;\n");
+ buf_appendf(contents, "pub const link_mode = LinkMode.Dynamic;\n");
buf_appendf(contents, "pub const is_test = false;\n");
buf_appendf(contents, "pub const single_threaded = %s;\n", bool_to_str(g->is_single_threaded));
buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi);
try this. should be OK because this applies only to building zig1.o
I'm not sure why the uname
didn't get the correct linux version though, that's another mystery here.
try this. should be OK because this applies only to building zig1.o
Tried and confirmed that it fixed the issue for me at least. Should this be PR'd?
Is libc bundled with zig or there are two versions in my computer.
/ws/projects/zig/sqlite :: # ldd --version
ldd (Ubuntu GLIBC 2.31-0ubuntu9) 2.31
pub const os = Os{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 5,
.minor = 4,
.patch = 0,
},
.max = .{
.major = 5,
.minor = 4,
.patch = 0,
},
},
.glibc = .{
.major = 2,
.minor = 17,
.patch = 0,
},
}},
};
#6227 #5882
Does the latter problem mean Zig should search the other places like DT_RPATH, LD_LIBRARY_PATH, /lib and /usr/lib similar to ld?
Shit hits the fan pretty quickly if you want to do things right, here's a quote from ld.so manpage:
When resolving shared object dependencies, the dynamic linker first
inspects each dependency string to see if it contains a slash (this
can occur if a shared object pathname containing slashes was
specified at link time). If a slash is found, then the dependency
string is interpreted as a (relative or absolute) pathname, and the
shared object is loaded using that pathname.
If a shared object dependency does not contain a slash, then it is
searched for in the following order:
o Using the directories specified in the DT_RPATH dynamic section
attribute of the binary if present and DT_RUNPATH attribute does
not exist. Use of DT_RPATH is deprecated.
o Using the environment variable LD_LIBRARY_PATH, unless the
executable is being run in secure-execution mode (see below), in
which case this variable is ignored.
o Using the directories specified in the DT_RUNPATH dynamic section
attribute of the binary if present. Such directories are searched
only to find those objects required by DT_NEEDED (direct
dependencies) entries and do not apply to those objects' children,
which must themselves have their own DT_RUNPATH entries. This is
unlike DT_RPATH, which is applied to searches for all children in
the dependency tree.
o From the cache file /etc/ld.so.cache, which contains a compiled
list of candidate shared objects previously found in the augmented
library path. If, however, the binary was linked with the -z
nodeflib linker option, shared objects in the default paths are
skipped. Shared objects installed in hardware capability
directories (see below) are preferred to other shared objects.
o In the default path /lib, and then /usr/lib. (On some 64-bit
architectures, the default paths for 64-bit shared objects are
/lib64, and then /usr/lib64.) If the binary was linked with the
-z nodeflib linker option, this step is skipped.
The regression should be fixed in 2de53592a1d84a1476f662e20d7339d25d4716fe. I'd like to leave this issue open until the logic is improved to match ld behavior that @LemonBoy posted above.
@ifreund one thing I still want to figure out, is why did zig get the wrong OS version? 3.16.0...5.5.5 means it failed to extract the value from the uname
syscall.
Here's what I get from the uname syscall on my machine using the following code:
const std = @import("std");
pub fn main() !void {
std.debug.print("{}\n", .{std.os.uname()});
}
utsname{ .sysname = Linux, .nodename = trantor, .release = 5.8.12_1, .version = #1 SMP Sat Sep 26 18:03:25 UTC 2020, .machine = x86_64, .domainname = (none) }
Hi, I have the same issue on Archlinux. When I try to build
const std = @import("std");
const mman = @cImport({
@cDefine("_GNU_SOURCE", {});
@cInclude("sys/mman.h");
});
pub fn main() void {
var fd = mman.memfd_create("test", 0);
std.
std.debug.print("fd = {}\n", .{fd});
}
I get linking error:
lld: error: undefined symbol: memfd_create
>>> referenced by main.zig:9
>>> /home/vesim/pro/zsmrt/zig-cache/o/2367e7736b5f96ca670c5e9d97d3d0de/init-exe.o:(main.0)
>>> did you mean: memfd_create@GLIBC_2.27
>>> defined in: /home/vesim/.cache/zig/o/54b93fc35ead95cbaefb74de730f28a8/libc.so.6
error: LLDReportedFailure
Enviroment:
zig build --show-builtin
:
pub const os = Os{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 5,
.minor = 9,
.patch = 10,
},
.max = .{
.major = 5,
.minor = 9,
.patch = 10,
},
},
.glibc = .{
.major = 2,
.minor = 17,
.patch = 0,
},
}},
};
zig version
:
0.7.0+39336fd2e
Packages versions:
glibc 2.32-5
llvm 11.0.0-1
gcc 10.2.0-3
@vesim987, whats the output of readelf -d /usr/bin/env
?
@LemonBoy
Dynamic section at offset 0xabd8 contains 27 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000c (INIT) 0x2000
0x000000000000000d (FINI) 0x7184
0x0000000000000019 (INIT_ARRAY) 0xb9d0
0x000000000000001b (INIT_ARRAYSZ) 8 (bytes)
0x000000000000001a (FINI_ARRAY) 0xb9d8
0x000000000000001c (FINI_ARRAYSZ) 8 (bytes)
0x000000006ffffef5 (GNU_HASH) 0x308
0x0000000000000005 (STRTAB) 0xb10
0x0000000000000006 (SYMTAB) 0x390
0x000000000000000a (STRSZ) 902 (bytes)
0x000000000000000b (SYMENT) 24 (bytes)
0x0000000000000015 (DEBUG) 0x0
0x0000000000000003 (PLTGOT) 0xbdc8
0x0000000000000002 (PLTRELSZ) 24 (bytes)
0x0000000000000014 (PLTREL) RELA
0x0000000000000017 (JMPREL) 0x1928
0x0000000000000007 (RELA) 0xf98
0x0000000000000008 (RELASZ) 2448 (bytes)
0x0000000000000009 (RELAENT) 24 (bytes)
0x0000000000000018 (BIND_NOW)
0x000000006ffffffb (FLAGS_1) Flags: NOW PIE
0x000000006ffffffe (VERNEED) 0xf38
0x000000006fffffff (VERNEEDNUM) 1
0x000000006ffffff0 (VERSYM) 0xe96
0x000000006ffffff9 (RELACOUNT) 28
0x0000000000000000 (NULL) 0x0```
Perhaps it's time to reconsider whether the extra-smart, super-complex and fallible heuristic used here is pulling its own weight.
A simpler detection method would be to invoke ldd --version
and scrape the output, it's not that nice but sounds better than misdetecting the libc version and/or having to re-implement the whole ld lookup logic.
A simpler detection method would be to invoke
ldd --version
and scrape the output,
No. I veto adding a dependency on ldd
.
Looks like there is a regression:
zig version
: 0.10.0
ldd --version
:
ldd (Gentoo 2.35-r5 p7) 2.35
...
zig build-exe --show-builtin
:
...
pub const os = std.Target.Os{
.tag = .linux,
.version_range = .{ .linux = .{
.range = .{
.min = .{
.major = 5,
.minor = 18,
.patch = 1,
},
.max = .{
.major = 5,
.minor = 18,
.patch = 1,
},
},
.glibc = .{
.major = 2,
.minor = 19,
.patch = 0,
},
}},
};
...
Same on Arch Linux.
Problem is that on Arch /lib64/ld-linux-x86-64.so.2
is not a symlink after all
For that matter, neither is /lib64/libc.so.6
:
$ file /lib64/ld-linux-x86-64.so.2
/lib64/ld-linux-x86-64.so.2: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), static-pie linked, BuildID[sha1]=0effd0e43efa4468d3c31871c93af0b7f3005673, stripped
$ file /lib64/libc.so.6
/lib64/libc.so.6: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /usr/lib/ld-linux-x86-64.so.2, BuildID[sha1]=60df1df31f02a7b23da83e8ef923359885b81492, for GNU/Linux 4.4.0, stripped
They do both support being executed with a --version
flag, but the output is not really intended to be machine parseable:
$ /lib64/ld-linux-x86-64.so.2 --version
ld.so (GNU libc) stable release version 2.35.
Copyright (C) 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Maybe we can use confstr() with name
_CS_GNU_LIBC_VERSION
for detecting glibc version? (upd: oh, it requires linking libc)
upd: or execute getconf GNU_LIBC_VERSION
https://pubs.opengroup.org/onlinepubs/000095399/utilities/getconf.html
Could I get someone affected by this issue to verify that #12788 indeed solves it?