ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.

Home Page:https://ziglang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

zig cc regression in 0.9.0

motiejus opened this issue · comments

Zig Version

0.9.0

Steps to Reproduce

I am running on debian buster (glibc 2.28).

git clone https://github.com/protocolbuffers/protobuf/
mkdir -p protobuf/cmake/build
cd protobuf/cmake/build
CFLAGS=-g CC=~/dev/zig/build/zig\ cc\ -target\ x86_64-linux-gnu.2.28 CXX=~/dev/zig/build/zig\ c++\ -target\ x86_64-linux-gnu.2.28 cmake ..
make -j$(nproc) # parallel make has a tendency to fail with many cores, thus ...
make
./protoc -h | head -1

git bisect points to 19ca241

19ca2415f26b07b399a60fd17a4cf85f290da0fd is the first bad commit
commit 19ca2415f26b07b399a60fd17a4cf85f290da0fd                                                                           
Author: Andrew Kelley <andrew@ziglang.org>                     
Date:   Wed Dec 15 00:22:38 2021 -0700                       
                                                                                                                     
    update glibc start files to 2.34                                  
                                                              
    This commit introduces tools/update_glibc.zig to update the start files       
    for next time.                                                                                                                                                   
                                                                
    Some notable changes in recent glibc:                      
                                                                                                                          
     * abi-note.S has been changed to abi-note.c but we resist the change to
       keep it easier to compile the start files.            
     * elf-init.c has been deleted upstream. Further testing should be done                                          
       to verify that binaries against glibc omitting elf-init.c still run
       properly on oldel glibc linux systems.                 
                                                                                  
    Closes #4926

Expected Behavior

./protoc -h | head -1
Usage: ./protoc [OPTION] PROTO_FILES

Actual Behavior

./protoc -h
Segmentation fault

Here is a backtrace:

user@motiejus:~/code/protobuf/cmake/build$ gdb ./protoc
GNU gdb (Debian 8.2.1-2+b3) 8.2.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./protoc...(no debugging symbols found)...done.
(gdb) run
Starting program: /home/user/code/protobuf/cmake/build/protoc
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000793c50 in std::__1::basic_ostream<char, std::__1::char_traits<char> >::sentry::sentry(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) ()                                                                                                                                                            
(gdb) bt full
#0  0x0000000000793c50 in std::__1::basic_ostream<char, std::__1::char_traits<char> >::sentry::sentry(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) ()
No symbol table info available.
#1  0x000000000049bf3b in std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) ()
No symbol table info available.
#2  0x000000000049397c in google::protobuf::compiler::CommandLineInterface::PrintHelpText() ()
No symbol table info available.
#3  0x000000000048f196 in google::protobuf::compiler::CommandLineInterface::ParseArguments(int, char const* const*) ()
No symbol table info available.
#4  0x000000000048d46b in google::protobuf::compiler::CommandLineInterface::Run(int, char const* const*) ()
No symbol table info available.
#5  0x00000000004884be in google::protobuf::compiler::ProtobufMain(int, char**) ()
No symbol table info available.
#6  0x0000000000488a41 in main ()
No symbol table info available.
(gdb) 

Trying to run a simple hello world compiled with zig c++ fails with a similar backtrace:

// main.cpp
#include <iostream>

using namespace std;

int main() {
	cout << "hello world" << endl;
}
$ zig c++ main.cpp
$ ./a.out 
Segmentation fault

Backtrace:

gef➤  bt
#0  0x0000000000235f80 in std::__1::basic_ostream<char, std::__1::char_traits<char> >::sentry::sentry(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) ()
#1  0x0000000000219cbb in std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::__put_character_sequence<char, std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*, unsigned long) ()
#2  0x0000000000219b84 in main ()

This is a test program to create a global which has constructor/destructor that must be called before/after main.

note: I used zig master (c710d5e)


what.cpp

#include <cstdio>

struct first
{
    first() { printf("first()\n"); }
    ~first() { printf("~first()\n"); }
};

first f;

int main()
{
    printf("main: first is at address %p\n", &f);
    return 0;
}

expected output

first()
main: first is at address 0x557fd34d0049
~first()
  • ok: archlinux g++ -o what what.cpp
  • ok: archlinux clang++ -o what what.cpp
  • ok: archlinux zig c++ -o what what.cpp -target x86_64-linux-musl

fail: archlinux zig c++ -o what what.cpp

main: first is at address 0x22f9e0

No global ctor/dtor called. I suspect this is a strong hint as to what's causing OP's issue.

mmm got hit by this as well. (and I guess so will anyone trying to build c++ code..)

diff --git a/test/standalone/c_compiler/test.cpp b/test/standalone/c_compiler/test.cpp
index f10a9e0c0..bebe21096 100644
--- a/test/standalone/c_compiler/test.cpp
+++ b/test/standalone/c_compiler/test.cpp
@@ -12,10 +12,17 @@ private:
        int m_val;
 };
 
+
+volatile int runtime_val = 456;
+CTest global(runtime_val);     // test if global initializers are called.
+
 int main (int argc, char *argv[])
 {
+       assert(global.getVal() == 456);
+
        auto* t = new CTest(123);
        assert(t->getVal()!=456);
+
     if (argc>1) t->printVal();
        bool ok = t->getVal() == 123;
        delete t;

Adding the above diff to the test suite makes it fail (on Arch linux, which is still latest glibc 2.33 at this point)

Looking at 19ca241
it seems that in glibc the elf-init.c file contents was actually merged into a new file
https://repo.or.cz/glibc.git/blob/HEAD:/csu/libc-start.c

what would be the best fix?

  1. trying to make update_glibc.zig include the new file(s?)
  2. or trying to port the behaviour of elf-init.c over into some zig start file somewhere?

(I guess "1.", because while elf-init.c seems pretty straight forward, the new libc-start.c includes lots of tricky stuff)

looked a bit into it.
doesn't seem so easy..

From what I understand at this point (== very little :), the _start function needs to be modified depending on the target glibc version.
19ca241#diff-5afb6344bc5a0f0ab733f5769bf405f71c6af77815c88326da50d5fdcdd86f2b
"These used to be the addresses of .fini and .init." -> now passes null and will not work with the __libc_start_main from previous glibc.so

So I guess a different start should be generated depending on the targetted glibc. which seems non trivial, given that it is very platform specific for every arch...
Maybe using a mechanism to use the start.s from the correct target glibc version? (but I guess there are dependencies to the rest of the glibc source code..)
or making some custom start generation code in zig?

mmm I guess I'll first rollback to an older zig to build my c++ code,
and think some more about how to deal with this...

Thanks for the report. I verified that with 1e481df, a viable protobuf gets compiled with the provided reproduction steps. Thanks @xxxbxxx!