C’è un modo in cui un programma C / C ++ può bloccarsi prima di main ()?

C’è un modo in cui un programma può bloccarsi prima di main ()?

Con gcc, puoi taggare una funzione con l’ attributo constructor (che fa sì che la funzione venga eseguita prima del main ). Nella seguente funzione, verrà chiamato premain prima di main :

 #include  void premain() __attribute__ ((constructor)); void premain() { fputs("premain\n", stdout); } int main() { fputs("main\n", stdout); return 0; } 

Quindi, se c’è un bug che si blocca in premain si bloccherà prima di main .

Sì, almeno sotto Windows. Se il programma utilizza DLL, possono essere caricati prima dell’avvio di main() . Le funzioni DllMain di quelle DLL verranno eseguite prima di main() . Se incontrano un errore, potrebbero causare l’arresto o l’arresto dell’intero processo.

Se si dispone di un programma C ++, è ansible inizializzare variabili e oggetti tramite funzioni e costruttori prima di immettere main. Un bug in uno di questi potrebbe causare il crash di un programma.

certamente in c ++; gli oggetti statici con i contromanti verranno chiamati prima di main – possono morire

non sono sicuro di c

ecco il campione

 class X { public: X() { char *x = 0; *x = 1; } }; X x; int main() { return 0; } 

questo si bloccherà prima di main

La risposta semplice è: .

Più specificamente, possiamo distinguere tra due cause per questo. Li chiamerò dipendenti dall’implementazione e indipendenti dall’implementazione .

L’unico caso che non dipende affatto dal proprio ambiente è quello degli oggetti statici in C ++, che è stato menzionato qui. Il seguente codice muore prima di main() :

 #include  class Useless { public: Useless() { throw "You can't construct me!"; } }; static Useless object; int main() { std::cout << "This will never be printed" << std::endl; return 0; } 

Più interessanti sono le cause dipendenti dalla piattaforma . Alcuni sono stati menzionati qui. Uno che è stato menzionato qui un paio di volte è stato l'uso di librerie collegate dynamicmente (DLL in Windows, SO in Linux, ecc.) - se il caricatore del sistema operativo le carica prima di main() , potrebbero causare la morte della tua applicazione main() .

Una versione più generale di questa causa sta parlando di tutte le cose che il punto di ingresso del tuo binario fa prima di chiamare il tuo punto di ingresso ( main() ). Di solito quando costruisci il tuo binario c'è un blocco di codice piuttosto serio che viene chiamato quando il caricatore del tuo sistema operativo inizia ad eseguire il tuo binario, e quando ha finito chiama il tuo main() . Una cosa comune a questo codice è l'inizializzazione della libreria standard C / C ++. Questo codice può fallire per un numero qualsiasi di ragioni (carenza di qualsiasi tipo di risorsa di sistema che tenta di allocare per uno).

Un modo interessante per un binario di eseguire il codice prima di main() su Windows sta usando i callback TLS (google ti dirà di più su di loro). Questa tecnica si trova di solito nel malware come un trucco anti-debug di base (questo trucco usato per ingannare Ollydbg allora, non so se lo fa ancora).

Il punto è che la tua domanda è in realtà equivalente a "c'è un modo in cui il caricamento di un file binario dovrebbe causare l'esecuzione del codice utente prima del codice in main() ?", E la risposta è infernale, sì!

Qualsiasi programma che si basa su oggetti condivisi (DLL) che vengono caricati prima che il main possa fallire prima di main.

Sotto il codice Linux nella libreria del linker dinamico (ld – *. So) viene eseguito per fornire dipendenze tutte le librerie ben prima di main. Se non è ansible individuare eventuali librerie necessarie, disporre di autorizzazioni che non consentono di accedervi, non sono file normali o non hanno alcun simbolo che il linker dinamico che ha collegato il programma abbia pensato che avrebbe dovuto ha collegato il tuo programma, quindi questo può causare un errore.

Inoltre, ogni libreria può eseguire del codice quando è collegato. Ciò è dovuto principalmente al fatto che la libreria potrebbe aver bisogno di colbind più librerie o potrebbe aver bisogno di eseguire alcuni costruttori (anche in un programma C, le librerie potrebbero avere qualche C ++ o qualcos’altro che usi i costruttori). Inoltre, i programmi C standard hanno già creato lo stdio FILE, stdin, stdout e stderr. Su molti sistemi questi possono anche essere chiusi. Ciò implica che sono anche gratuiti () ed, il che implica che essi (e i loro buffer) erano malloc () ed, che può fallire. Suggerisce anche che potrebbero aver fatto altre cose sui descrittori di file che quelle strutture FILE rappresentano, cosa che potrebbe fallire.

Altre cose che potrebbero accadere potrebbero essere se il sistema operativo dovesse rovinare la configurazione delle variabili ambientali e / o degli argomenti della riga di comando che sono stati passati al programma. È probabile che il codice prima di main abbia avuto qualcosa con questi dati prima di chiamare main.

Molte cose accadono prima di main. Ognuno di loro può con successo fallire in modo fatale.

Non sono sicuro, ma se hai una variabile globale come questa:

 static SomeClass object; int main(){ return 0; } 

Il costruttore ‘SomeClass’ potrebbe eventualmente arrestare il programma prima dell’esecuzione principale.

Ci sono molte possibilità.

Per prima cosa, dobbiamo capire cosa succede realmente prima che la main venga eseguita:

  • Carico di librerie dinamiche
  • Inizializzazione di globals
  • Uno di alcuni compilatori, alcune funzioni possono essere eseguite esplicitamente

Ora, tutto ciò può causare un arresto anomalo in diversi modi:

  • il solito comportamento indefinito (dereferenziamento puntatore nullo, accesso alla memoria non dovrebbe …)
  • un’eccezione generata> poiché non vi è alcun catch , viene chiamato il termine e il programma termina

È davvero fastidioso, ovviamente, e probabilmente difficile da eseguire il debug, ed è per questo che dovresti astenermi dall’eseguire il codice prima del main il più ansible, e preferire l’inizializzazione pigra se puoi, o l’inizializzazione esplicita all’interno del main .

Naturalmente, quando si verifica un errore della DLL e non è ansible modificarlo, ci si trova in un mondo di dolore.

Una specie di: http://blog.ksplice.com/2010/03/libc-free-world/

Se si compila senza libreria standard, in questo modo: gcc -nostdlib -o ciao ciao.c

non saprà come eseguire main () e si bloccherà.

Gli oggetti globali e statici in un programma C ++ chiameranno i loro costruttori prima che venga eseguita la prima istruzione in main (), quindi un bug in uno dei costruttori può causare un arresto anomalo.

Questo non può accadere nei programmi C, però.

Dipende da cosa intendi per “prima del main”, ma se intendi “prima che il tuo codice in main venga effettivamente eseguito”, allora posso pensare ad un esempio: se dichiari un array grande come variabile locale in main, e la dimensione di questo array supera lo spazio di stack disponibile, quindi è ansible che si stack overflow un stack overflow nella voce main, prima dell’esecuzione della prima riga di codice.

Un esempio un po ‘forzato potrebbe essere:

 int a = 1; int b = 0; int c = a / b; int main() { return 0; } 

È improbabile che tu possa mai fare qualcosa del genere, ma se stai facendo un sacco di macro-magia, è del tutto ansible.

 class Crash { public: Crash( int* p ) { *p = 0; } }; static Crash static_crash( 0 ); void main() { } 

Certo, se c’è un bug nel sistema operativo o nel codice di runtime. C ++ è particolarmente noto per questo comportamento, ma può ancora succedere in C.

Non hai detto quale piattaforma / libc. Nel mondo embedded ci sono spesso molte cose che funzionano prima di main() – in gran parte dovuto alla configurazione della piattaforma – che possono andare storte. (O in effetti se stai usando uno script di linker funky su un normale sistema operativo, tutte le scommesse sono distriggerste, ma immagino che sia piuttosto raro.)

alcune librerie di astrazione della piattaforma sovrascrivono (io personalmente conosco solo le librerie C ++ come Qt o ACE, che fanno questo, ma forse alcune librerie C fanno qualcosa di simile) “main”, in modo che specifichino una main specifica della piattaforma come una int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ); e configura alcune cose da libreria, converti le discussioni da riga di comando al normale int argc, char* argv[] e poi chiama il normale int main(int argc, char* argv[])

Ovviamente tali librerie potrebbero portare ad un crash quando non sono state implementate correttamente (forse causa di argomenti della riga di comando malformati).

E per le persone che non lo sanno, questo potrebbe sembrare un incidente prima di main

Ho affrontato lo stesso problema. La causa principale trovata era .. Troppe variabili locali (enormi matrici) sono state inizializzate nel processo principale, portando le dimensioni delle variabili locali superiori a 1,5 mb.
Ciò si traduce in un grande salto come il puntatore dello stack è abbastanza grande e il sistema operativo rileva questo salto come non valido e si blocca il programma in quanto potrebbe essere dannoso.

Per eseguire il debug di questo.
1. Accendi GDB
2. Aggiungi un breakpoint principale
3. smontare il main
4. Controlla per $ 0xGGGGGG,% esp
Se questo valore GGGGGG è troppo alto, vedrai lo stesso problema di me.

Quindi controlla la dimensione totale di tutte le variabili locali nel principale.