简体   繁体   中英

Why linker does not complain about multiple definitions when linking against shared and static

I've encountered recently on a problem with static initialization fiasco in the code that I was developing. It made me realize my lack of knowledge about linking process and global variables initialization so I've found this this very interesting talks at cppcon about globals, linking and possible issue with having static library embedded in shared and linking both at the same time (with globals defined). What was basically said there is that when having following structure:

//static.hpp
#pragma once

#include <string>

extern std::string globalString;

//static.cpp
#include "static.hpp"

std::string globalString;

//shared.hpp
#pragma once

#include "static.hpp"
#include <string>

std::string& getGlobalString();

//shared.cpp
#include "shared.hpp"
#include "static.hpp"

std::string& getGlobalString(){
  return globalString;
}

//main.cpp
#include "static.hpp"
#include "shared.hpp"
#include <iostream>

int main(){
    std::cout << "Global variable: " << globalString <<  std::endl;
    std::cout << "Global var acccesed through shared lib: " << getGlobalString() << std::endl;
    return 0;
}

All compiled with:

clang++ -c -std=c++14 -fpic static.cpp
clang++ -c -std=c++14 -fpic shared.cpp
clang++ -c -std=c++14 main.cpp
ar rsc libstatic.a static.o
clang++ -shared -o libshared.so shared.o -L./ -lstatic
clang++ -L./ -Wl,-rpath=./ main.o -lstatic -lshared

My lead to segmentation fault due to calling multiple times constructor and destructor of the same object. This is surprising as I took this as invariant that every object constructor will be called exactly once!

  • What standard says about calling constructor/destructor multiple times?
  • If in that case the global of static i embedded in both main.o and libshared.so the does it mean that rule of having one definition is broken? Why linker does not complain about having second definition available while linking main?
  • One of suggested ways to establish construction and destruction order when having at least two global in separate translation unit would be to Initialize when first use. This is however ensures only construction order as far as I understand. What about destruction order? How to control?

This is surprising as I took this as invariant that every object constructor will be called exactly once!

In a properly constructed binary that would be true. It is not necessarily true in a binary with an ODR violation.

What standard says about calling constructor/destructor multiple times?

The standard says that in a properly constructed program, constructor / destructor is called exactly once. In a program with an ODR violation, anything can happen (undefined behavior).

If in that case the global of static i embedded in both main.o and libshared.so the does it mean that rule of having one definition is broken?

Yes.

Why linker does not complain about having second definition available while linking main?

As far as linker is concerned, there is nothing wrong with your program. From the linker perspective, defining a global in both static and shared library is perfectly kosher. See also this answer .

One of suggested ways to establish construction and destruction order when having at least two global in separate translation unit would be to Initialize when first use. This is however ensures only construction order as far as I understand.

Correct. This is a solution for a different problem: two globals A and B defined in separate translation units.

You don't have that problem, you have a totally different one (ODR violation).

What about destruction order? How to control?

In a properly constructed program, destruction order is guaranteed to be reverse of construction order.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM