0

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?
Adam Stepniak
  • 815
  • 6
  • 21
  • ODR applies to the program being compiled. The same symbol can be defined in your program and a linked shared library without any error. – cdhowie Jul 18 '20 at 12:40
  • [What’s the “static initialization order ‘fiasco’ (problem)”?](https://isocpp.org/wiki/faq/ctors#static-init-order) – Jesper Juhl Jul 18 '20 at 13:14

1 Answers1

1

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.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362