Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linker symbols leak to unrelated translation units, leading to linker errors #12

Closed
peterazmanov opened this issue Jun 25, 2018 · 7 comments

Comments

@peterazmanov
Copy link
Contributor

Linker fails with "multiple definition of ..." when compiling code that uses Boost.Serialization.

Steps to reproduce:

  • unzip zapcc_test.zip
  • create bin subdirectory
  • cd bin
  • CC=zapcc CXX=zapcc++ cmake ..
  • make

Output:

[ 33%] Building CXX object CMakeFiles/zapcc-test.dir/a.cpp.o
[ 66%] Building CXX object CMakeFiles/zapcc-test.dir/main.cpp.o
[100%] Linking CXX executable zapcc-test
CMakeFiles/zapcc-test.dir/main.cpp.o:(.rodata+0x10): multiple definition of `typeinfo for A'
CMakeFiles/zapcc-test.dir/a.cpp.o:(.rodata+0x10): first defined here
CMakeFiles/zapcc-test.dir/main.cpp.o:(.rodata+0x0): multiple definition of `typeinfo name for A'
CMakeFiles/zapcc-test.dir/a.cpp.o:(.rodata+0x0): first defined here
zapcc: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [CMakeFiles/zapcc-test.dir/build.make:100: zapcc-test] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/zapcc-test.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

System: Linux archlinux 4.17.2-1-ARCH #1 SMP PREEMPT Sat Jun 16 11:08:59 UTC 2018 x86_64 GNU/Linux
ZapCC is built from commit 01ff39e (2018.06.21)
Boost version: 1.67.0

The example compiles and links fine with Clang 5.0/6.0 and GCC 8.1.1

The problem occures when serializing polymorphic base class. This causes registration in internal singleton of Boost.Serialization. Somehow vtable-related symbols from previous translation units are included in subsequent unrelated translation units.

Example has the following structure:

  • a.h contains definitions for base class B and class A derived from B
  • a.cpp contains explicitly instantiated serialization method for class A, its default constructor and destructor. Placement of constructor and destructor is crucial for example to fail as it causes symbols to be marked as 'global', otherwise they would be marked as 'weak' - multiple weak symbols are allowed by linker
  • main.cpp contains empty main function and struct C with empty serialization. Without C example compiles and links without errors.

a.h:

#pragma once

#include <boost/serialization/access.hpp>

class B
{
public:
    virtual ~B() = default;

private:
    friend class boost::serialization::access;

    template< class Archive >
    void serialize( Archive & /* ar */, unsigned int const /* version */ )
    {}
};

class A
    : public B
{
public:
    A();

    virtual ~A();

private:
    friend class boost::serialization::access;

    template< class Archive >
    void serialize( Archive & ar, unsigned int version );
};

a.cpp:

#include "a.h"

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

A::A() = default;
A::~A() = default;

template< class Archive >
void A::serialize( Archive & ar, unsigned int /* version */ )
{
    ar & boost::serialization::base_object<B>(*this);
}

template void A::serialize( boost::archive::binary_oarchive & ar, unsigned int version );
template void A::serialize( boost::archive::binary_iarchive & ar, unsigned int version );

main.cpp:

#include <boost/serialization/access.hpp>

#include <boost/archive/binary_iarchive.hpp>
#include <boost/archive/binary_oarchive.hpp>

struct C
{
private:
    friend class boost::serialization::access;

    template< class Archive >
    void serialize( Archive & /* ar */, unsigned int const /* version */ )
    {}
};

template void C::serialize( boost::archive::binary_oarchive & ar, unsigned int const version );
template void C::serialize( boost::archive::binary_iarchive & ar, unsigned int const version );

int main()
{
    return 0;
}

zapcc_test.zip

@yrnkrn
Copy link
Owner

yrnkrn commented Jun 25, 2018

Deciding whether to emit template instantiation-related symbols with cached includes is a very complex problem. Boost had already provided zapcc lots of good tests in tools/clang/test/zapcc/multi , this is probably another... this example will need to be completely c-reduced first, will look into this.

@yrnkrn
Copy link
Owner

yrnkrn commented Jun 27, 2018

Could you c-reduce (https://embed.cs.utah.edu/creduce) this example code to independent header and source files? final version would be few lines each, similar to https://github.com/yrnkrn/zapcc/tree/master/tools/clang/test/zapcc/multi/template-function-local-var
also reduced from Boost. Thanks!

@peterazmanov
Copy link
Contributor Author

peterazmanov commented Jun 29, 2018

I managed to reduce (with the help of creduce) the test to the following:
zapcc_test_reduced.zip

reduced_boost.h:

#pragma once

template <class A, class B>
void void_cast_register()  __attribute__ ((__used__));

template <class A, class B>
void void_cast_register()
{
    (void)dynamic_cast<A *>((B *)nullptr);
}

a.h:

#pragma once

struct B
{
  virtual ~B() = default;
};

struct A : B
{
  ~A();
};

a.cpp:

#include "a.h"
#include "reduced_boost.h"

A::~A()
{
  void_cast_register<A, B>();
}

main.cpp:

#include "reduced_boost.h"

int main()
{}

@yrnkrn
Copy link
Owner

yrnkrn commented Jun 29, 2018

Nice & clean reduce, looking at the problem.

@yrnkrn
Copy link
Owner

yrnkrn commented Jun 30, 2018

https://guides.github.com/features/mastering-markdown/
12.zip

Normalized to our usual test script.

@yrnkrn
Copy link
Owner

yrnkrn commented Jul 1, 2018

Fix reduced + new LIT test in 194583e.
If original problem still persists, please open a new issue.

@yrnkrn yrnkrn closed this as completed Jul 1, 2018
@peterazmanov
Copy link
Contributor Author

Fix solved the problem. Checked both reduced and non-reduced versions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants