2010-03-22 13 views
7

Sto provando a rintracciare un crash molto strano. Ciò che è così strano è una soluzione che qualcuno ha scoperto e che non posso spiegare.come può cambiare il comportamento del programma eseguito

La soluzione è questo piccolo programma che mi riferisco a come 'runner':

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
    if (argc == 1) 
    { 
     fprintf(stderr, "Usage: %s prog [args ...]\n", argv[0]); 
     return 1; 
    } 

    execvp(argv[1], argv + 1); 

    fprintf(stderr, "execv failed: %s\n", strerror(errno)); 

    // If exec returns because the program is not found or we 
    // don't have the appropriate permission 
    return 255; 
} 

Come si può vedere, tutto questo programma non fa altro che utilizzare execvp a sostituire se stesso con un programma diverso.

il programma si blocca quando viene direttamente richiamato dalla riga di comando:

/path/to/prog args # this crashes 

ma funziona bene quando è indirettamente richiamato tramite il mio corridore spessore:

/path/to/runner /path/to/prog args # works successfully 

Per la vita di me, Posso capire come avere un exec in più può cambiare il comportamento del programma in esecuzione (come si può vedere il programma non cambia l'ambiente).

Alcuni dati sullo schianto. Lo stesso crash si sta verificando nel runtime di C++. In particolare, quando il programma esegue un throw, la versione che si blocca in modo errato ritiene che non vi sia alcuna corrispondenza corrispondente (anche se esiste) e chiama terminate. Quando invoco il programma tramite il corridore, l'eccezione viene catturata correttamente.

La mia domanda è un'idea del perché l'exec extra cambi il comportamento del programma eseguito?

+0

Non so: ma execvp modifica la directory di lavoro? Quali argomenti stai passando? –

+0

@MartinYork - AFAIK, 'execvp' non cambia mai la directory di lavoro (che richiede una chiamata a' chdir' e il corridore non lo fa). Gli argomenti specifici sono irrilevanti; il comportamento descritto è indipendente dagli argomenti specifici passati al programma. –

+1

Fa la stessa cosa se usi 'execv()' invece di 'execvp()'? – caf

risposta

3

È possibile che i file .so caricati dal corridore stiano facendo funzionare correttamente il runee. Prova a ldd'ing ognuno dei binari e vedi se alcune librerie caricano versioni/posizioni diverse.

+1

Il problema è se 'ld-linux.so.2' esegue il mapping di un oggetto condiviso specifico nello spazio indirizzo prima del binario principale o dopo (il bug effettivo è altrove ma a causa di circostanze, il bug si manifesta solo quando l'SO è mappato con un indirizzo inferiore quindi il file binario principale). –

0

Come uno sparo al buio: il doppio exec può modificare l'ordine delle variabili di ambiente nella RAM.

L'ambiente è una struttura di memoria con puntatori; il kernel copia quella struttura nello spazio degli indirizzi del nuovo processo. L'effettivo ordine degli elementi nella RAM può cambiare durante quella copia (le variabili di ambiente non sono ordinate semanticamente, ma gli indirizzi nella RAM hanno un ordine). Con due exec(), l'ordine può essere modificato due volte.

Che un cambiamento nell'ordinamento delle stringhe nella RAM porti alla luce un errore è un po 'strano, ma sono accadute cose più strane.

+0

Grazie per il suggerimento ma non sembra essere così. Ho scaricato il blocco dell'ambiente grezzo e hanno lo stesso ordine in entrambi. –

0

Mi chiedo se stai passando qualcosa di diverso in argv [0] a ciò che è la shell. Non riesco a vedere chiaramente da quello che stai scrivendo sopra, ma è possibile che tu stia impostando argv [0] sul primo argomento effettivo del programma, mentre la shell lo imposta sul suo nome chiamato (ad esempio percorso completo o breve)

+0

@ MarkR - grazie per il tuo suggerimento. Ho modificato il runner in modo che 'argv [0]' non includesse il percorso. Sfortunatamente, sto ancora vedendo lo stesso comportamento. –

1

Forse il programma chiamato ha una perdita di memoria. Prova a eseguirlo con valgrind o altri strumenti di controllo della memoria. Dopo aver avuto un errore di memoria, tutto il resto è un comportamento indefinito (e quindi tutto può accadere).

+0

Altro che normale è ancora raggiungibile ai blocchi di uscita, Valgrind non rileva alcun errore sulla versione che termina (o la versione che non termina per quella materia). –

0

Immagino due cose che potresti confrontare tra versioni 'funzionanti' e 'in crash' - apri descrittori di file e gestori di segnale - come questi vengono trasmessi da exec.

Non riesco a vedere come sono il problema/essere diversi, ma potrebbe valer la pena eliminarli.

Problemi correlati