Určit statické inicializační pořadí po kompilaci?

hlasů
10

V jazyce C ++, vím, že překladač může zvolit inicializovat statické objekty v libovolném pořadí, které si zvolí (v závislosti na několika omezeními), a že obecně není možné vybrat nebo určit statické inicializační pořadí.

Avšak poté, co program byl sestaven kompilátor musí také rozhodnout o tom, aby se inicializovat tyto objekty. Existuje nějaký způsob, jak zjistit, z kompilované programu s ladění symboly, v jakém pořadí statické konstruktérů se bude jmenovat?

Kontext je následující: Mám značnou program, který je náhle segfaulting před main (), když je postaven pod novým toolchain. Buď se jedná o inicializaci pořadí problém statické, nebo je to něco, s jedním z knihoven, které se načítají špatně. Nicméně, když jsem ladit s gdb, místo havárie je jednoduše označena jako surový adresu bez symbolické informace nebo backtrace. Rád bych se rozhodnout, který z těchto dvou problémů, to je tím, že umístí zarážku na konstruktoru úplně první staticky inicializaci objektu, ale já nevím, jak zjistit, který objekt, který je.

Položena 03/08/2009 v 21:12
zdroj uživatelem
V jiných jazycích...                            


6 odpovědí

hlasů
11

G ++ na Linuxu, statický konstruktor a destruktor uspořádání je určeno ukazatelů funkcí v .ctors a .dtors sekcí. Všimněte si, že s dostatečnou ladění k dispozici, můžete skutečně získat backtrace:

(gdb) bt
#0  0xb7fe3402 in __kernel_vsyscall ()
#1  0xb7d59680 in *__GI_raise (sig=6)
    at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
#2  0xb7d5cd68 in *__GI_abort () at abort.c:88
#3  0x08048477 in foo::foo() ()
#4  0x0804844e in __static_initialization_and_destruction_0(int, int) ()
#5  0x0804846a in global constructors keyed to foo_inst ()
#6  0x0804850d in __do_global_ctors_aux ()
#7  0x08048318 in _init ()
#8  0x080484a9 in __libc_csu_init ()
#9  0xb7d4470c in __libc_start_main (main=0x8048414 <main>, argc=1,
    ubp_av=0xbfffcbc4, init=0x8048490 <__libc_csu_init>,
    fini=0x8048480 <__libc_csu_fini>, rtld_fini=0xb7ff2820 <_dl_fini>,
    stack_end=0xbfffcbbc) at libc-start.c:181
#10 0x08048381 in _start () at ../sysdeps/i386/elf/start.S:119

To je s ladění symboly pro libc a libstdc ++ nainstalován. Jak můžete vidět, crash zde došlo v foo :: foo () konstruktoru statického objektu foo_inst.

Chcete-li proniknout do procesu inicializace, můžete potom nastavit zarážku na __do_global_ctors_aux a krokovat jeho demontáž, myslím. Nebo jen čekat na to, aby nouzově získat backtrace jako výše uvedené.

Odpovězeno 03/08/2009 v 21:28
zdroj uživatelem

hlasů
7

Matthew Wilson poskytuje způsob, jak odpovědět na tuto otázku v této sekci (Safari Books Online je vyžadováno předplatné) z Imperfect C ++ . (Good kniha, mimochodem). Abychom to shrnuli, že vytvoří CUTrace.hzáhlaví, který vytváří statické instance třídy, která natiskne název souboru včetně zdrojového souboru (pomocí nestandardní preprocesoru makro __BASE_FILE__), když vytvořil, pak jsou CUTrace.hv každém zdrojovém souboru ,

To vyžaduje recompilation, ale mohou být snadno přidány #include „CUTrace.h“ a odstraněny pomocí skriptu, takže by neměl být příliš obtížné nastavit.

Odpovězeno 03/08/2009 v 21:39
zdroj uživatelem

hlasů
2

Mohl byste inicializovat fiktivní proměnné statické prostoru, a dal rozdělit body na těchto volání funkce?

extern "C" int breakOnMe () { return 0 };

int break1 = breakOnMe ();
float pi = 3.1415;
int break2 = breakOnMe ();
myClass x = myClass (1, 2, 3);

Pak v gdbběhu break breakOnMeještě před spuštěním programu. To by mělo činit gdb pauzu před každým na statické inicializaci.

Myslím, že by mělo fungovat .. Jsem trochu rezavý na gdbbing.

Odpovězeno 03/08/2009 v 21:19
zdroj uživatelem

hlasů
1

Naleznete objednávky TUS jsou inicializovat pomocí šablon jak je zdůrazněno v této otázce . To vyžaduje malý kousek změny kódu ke každému z TU, který vás zajímá:

// order.h
//

#ifndef INCLUDED_ORDER
#define INCLUDED_ORDER

#include <iostream>

inline int showCountAndFile (const char * file)
{
  static int cnt = 0;
  std::cout << file << ": " << cnt << std::endl;
  ++cnt;
  return cnt;
}

template <int & i>
class A {
  static int j;
};

template <int & i>
int A<i>::j = showCountAndFile (SRC_FILE);

namespace
{
  int dummyGlobal;
}
template class A<dummyGlobal>;

#endif

Základní myšlenkou je, že každá TU bude mít jinou jedinečnou adresu dummyGlobal a tak se šablona bude mít jiný instance v každém TU. Inicializace statických výsledků členskými ve výzvě k „showCountAndFile“, která pak vytiskne SRC_FILE (nastavený v TU) a aktuální hodnoty cnt, které proto ukáže pořadí.

Byste jej použít následujícím způsobem:

static const char * SRC_FILE=__FILE__;
#include "order.h"

int main ()
{
}
Odpovězeno 04/08/2009 v 09:29
zdroj uživatelem

hlasů
0

Ve skutečnosti, pomocí singletons můžete velmi efektivně v jazyce C ++ řídit pořadí inicializace globálních / static objekty.

Řekněme například, že máte:

class Abc
{
public:
    void foo();
};

a odpovídající objekt definovaný v globálním měřítku:

Abc abc;

Pak máte třídu:

class Def
{
public:
    Def()
    {
        abc.foo();
    }
};

který má také předmět definovaný v globálním měřítku:

Def def;

V této situaci, že nemáte kontrolu nad pořadí inicializace a pokud def inicializaci nejdříve, pak je pravděpodobné, že váš program spadne, protože je volání metody foo () na ABC, která dosud nebyla inicializována.

Řešením je mít funkci v globálním měřítku udělat něco takového:

Abc& abc()
{
    static Abc a;
    return a;
}

a pak Def bude vypadat nějak takto:

class Def
{
public:
    Def()
    {
        abc().foo();
    }
};

Tímto způsobem, abc je vždy zaručeno, že bude inicializovat před tím, než se používá proto, že se tak stane během prvního volání funkce ABC (). Stejně tak byste měli udělat to samé s Def globální objekt, aby byl zvyklý mít žádné neočekávané inicializační závislostí jeden.

Def& def()
{
    static Def d;
    return d;
}

Potřebujete-li striktně řídit pořadí inicializace kromě prostě dělat, že všechno se inicializuje před tím, než se používá, dát všechny globálních objektů v globálním ojedinělým takto.

struct Global
{
    Abc abc;
    Def def;
};

Global& global()
{
    static Global g;
    return g;
}

A aby odkazy na tyto položky takto:

//..some code
global().abc.foo();
//..more code here
global().def.bar();

Bez ohledu na to, který z nich jako první dostane volání, bude C ++ pravidla člen inicializační zaručit, že abc a def objekty jsou inicializovány v pořadí, v jakém jsou definovány v globální třídě.

Odpovězeno 06/03/2011 v 10:05
zdroj uživatelem

hlasů
0

g ++ poskytuje pomoc s tímto.
To není přenosný, ale jsem si jist, že v tomto bodě, která není vaším hlavním problémem.

http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#C_002b_002b-Attributes

Odpovězeno 03/08/2009 v 23:31
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more