You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is an issue that I've been trying to debug for the last few days, though the behavior appears to be consistent when compiling and running test programs using certain C libraries such as LMDB, libmdbx, or sqlite3.
To make reproduction simpler, I'll focus on LMDB as it has the least amount of code (and only one include path + two C source files to compile against).
These are the versions of clang and gcc I tested with:
$ clang --version
clang version 7.1.0 (tags/RELEASE_710/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /nix/store/3m76ry913ky4zb2frdbic3wa7gr69084-clang-7.1.0/bin
$ gcc --version
gcc (GCC) 9.3.0
Copyright (C) 2019 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.
These are the commands I used for compiling the test program:
$ clang test.c libraries/liblmdb/mdb.c libraries/liblmdb/midl.c -pthread -I libraries/liblmdb -o test
$ gcc test.c libraries/liblmdb/mdb.c libraries/liblmdb/midl.c -pthread -I libraries/liblmdb -o test
Running the program compiled with either clang or gcc, the program exits and completes successfully.
Now, if I were to use zig cc:
$ zig cc test.c libraries/liblmdb/mdb.c libraries/liblmdb/midl.c -pthread -I libraries/liblmdb -o test
$ ./test
Illegal instruction (core dumped)
Weird. Let's open it up on gdb:
Program received signal SIGILL, Illegal instruction.
0x00000000002136d3 in mdb_xcursor_init1 ()
(gdb) bt
#0 0x00000000002136d3 in mdb_xcursor_init1 ()
#1 0x0000000000209578 in mdb_cursor_put ()
#2 0x0000000000215e56 in mdb_put ()
#3 0x0000000000205443 in main ()
No useful backtrace. I did some printf debugging and there were no assertions hit nor dangling pointers / null pointers lurking amongst the code in mdb_xcursor_init1. So, let's view what's going on at the assembly-level.
... and for some reason, there is a ud2 (undefined) instruction right after ret.
Let's see how the assembly is like around the same code region for the binary emitted by gcc:
(gdb) b mdb_xcursor_init1
Breakpoint 1 at 0x40de0b
(gdb) r
Starting program: /home/lith/Desktop/lmdb-zig/test
warning: File "/nix/store/bpgdx6qqqzzi3szb0y3di3j3660f3wkj-glibc-2.31/lib/libthread_db-1.0.so" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load:/nix/store/isy60my0ijjzh49rscgdb1i2457nf7lp-gcc-9.3.0-lib".
warning: Unable to find libthread_db matching inferior's thread library, thread debugging will not be available.
Breakpoint 1, 0x000000000040de0b in mdb_xcursor_init1 ()
... and there is no ud2 instruction in the binary compiled with gcc after ret! Same goes for clang as well.
So in conclusion, this ud2 instruction for some reason keeps being emitted with C code compiled with Zig right after ret instructions of static methods. I reached the same issue with test code I made for libmdbx as well.
The same issue came up about illegal instructions for sqlite3 as well, which was brought to my attention by @nektro.
Might this be due to additional assertion checks emitted by the Zig compiler when analyzing static methods by chance? Or might this just be as a result of a C compiler flag that should've been set/cleared?
Would appreciate any assistance on this 🙏.
The text was updated successfully, but these errors were encountered:
😞 Yep, that's the reason why. Turns out LLVM's undefined behavior sanitizer mangled some of the methods in those C libraries. Is there any way to get a verbose warning during compile-time if UBsan gets triggered?
EDIT: It looks like there is an issue filed already for it at #5163. I'll close this issue.
This is an issue that I've been trying to debug for the last few days, though the behavior appears to be consistent when compiling and running test programs using certain C libraries such as LMDB, libmdbx, or sqlite3.
To make reproduction simpler, I'll focus on LMDB as it has the least amount of code (and only one include path + two C source files to compile against).
These are the versions of
clang
andgcc
I tested with:The test program (
test.c
) is as follows:These are the commands I used for compiling the test program:
Running the program compiled with either
clang
orgcc
, the program exits and completes successfully.Now, if I were to use
zig cc
:Weird. Let's open it up on
gdb
:No useful backtrace. I did some printf debugging and there were no assertions hit nor dangling pointers / null pointers lurking amongst the code in
mdb_xcursor_init1
. So, let's view what's going on at the assembly-level.... and for some reason, there is a
ud2
(undefined) instruction right afterret
.Let's see how the assembly is like around the same code region for the binary emitted by
gcc
:... and there is no
ud2
instruction in the binary compiled withgcc
afterret
! Same goes forclang
as well.So in conclusion, this
ud2
instruction for some reason keeps being emitted with C code compiled with Zig right afterret
instructions of static methods. I reached the same issue with test code I made for libmdbx as well.The same issue came up about illegal instructions for sqlite3 as well, which was brought to my attention by @nektro.
Might this be due to additional assertion checks emitted by the Zig compiler when analyzing static methods by chance? Or might this just be as a result of a C compiler flag that should've been set/cleared?
Would appreciate any assistance on this 🙏.
The text was updated successfully, but these errors were encountered: