Domanda

considerare il programma seguente

    char str[5];
    strcpy(str,"Hello12345678");
    printf("%s",str);

Quando si esegue questo programma dà segmentation fault.

Ma quando strcpy è sostituito con il seguente, il programma funziona bene.

strcpy(str,"Hello1234567");

Così questione si dovrebbe in crash quando si cerca di copiare a str qualsiasi altra stringa di lunghezza superiore a 5 caratteri.

Quindi, perché non si blocca per "Hello1234567" e solo crash per "Hello12345678", cioè di stringa con lunghezza di 13 o più di 13.

Il programma è stato eseguito su una macchina a 32 bit.

È stato utile?

Soluzione

Ci sono tre tipi di comportamento standard si dovrebbe essere interessato.

1 / comportamento definito . Questo funziona su tutte le implementazioni conformi. Utilizzare questa liberamente.

2 / il comportamento definito dall'implementazione . Come detto, dipende sull'attuazione ma almeno è ancora definito. Implementazioni sono tenuti a documentare quello che fanno in questi casi. Utilizzare questa opzione se non si cura di portabilità.

3 / comportamento non definito . Tutto può succedere. E vogliamo dire niente , fino ad includere l'intero computer collassando in un singolarità nuda e la deglutizione stesso, e una gran parte dei vostri compagni di lavoro. Non usare mai questo. Mai! Sul serio! Non farmi venire lì.

copia più di 4 caratteri e uno zero byte per un char[5] è un comportamento indefinito.

Scherzi a parte, non importa il motivo per cui il programma va in crash con 14 caratteri, ma non 13, si sta quasi certamente sovrascrivere alcuni non-schiantarsi informazioni sullo stack e il programma sarà molto probabilmente produrre risultati errati in ogni caso. In realtà, l'incidente è meglio almeno dal suo arresto si basandosi sui possibili effetti negativi.

Aumentare la dimensione della matrice per qualcosa di più adatto (char[14] in questo caso con le informazioni disponibili) o usare qualche altra struttura dati che possono far fronte.


Aggiornamento:

Dal momento che sembra così preoccupato con scoprire il motivo per cui un extra 7 caratteri non causa problemi, ma 8 caratteri non, facciamo prevedono la possibile il layout pila entrando main(). Dico "possibile", in quanto la disposizione effettiva dipende dalla convenzione di chiamata che il compilatore utilizza. Dal momento che il codice di avvio C chiama main() con argc e argv, lo stack all'inizio del main(), dopo l'attribuzione di spazio per un char[5], potrebbe essere la seguente:

+------------------------------------+
| C start-up code return address (4) |
| argc (4)                           |
| argv (4)                           |
| x = char[5] (5)                    |
+------------------------------------+

Quando si scrive il Hello1234567\0 byte con:

strcpy (x, "Hello1234567");

per x, sovrascrive il argc e argv ma, al ritorno dalla main(), va bene così. Specificamente Hello popola x, 1234 popola argv e 567\0 popola argc. A condizione che in realtà non tenta di usare argc e / o argv dopo, sarete a posto:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |
| argc (4)                           |   '567<NUL>'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Tuttavia, se si scrive Hello12345678\0 (notare l'extra "8") per x, sovrascrive il argc e argv e anche un byte di l'indirizzo di ritorno in modo che, quando main() tenta di tornare a il codice di avvio C, si spegne nella terra delle fate, invece:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |   '<NUL>'
| argc (4)                           |   '5678'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Ancora una volta, questo dipende interamente dalla convenzione di chiamata del compilatore. E 'possibile un compilatore diverso sarebbe sempre pad fuori array ad un multiplo di 4 byte e il codice non mancherebbe lì fino a quando hai scritto altri tre personaggi. Anche lo stesso compilatore può allocare variabili sul telaio pila diverso per garantire l'allineamento è soddisfatto.

Questo è ciò che si intende per non definita: non è so che cosa succederà

.

Altri suggerimenti

Si sta copiando allo stack, quindi è dipendente da ciò che il compilatore ha posto sullo stack, per la quantità di dati aggiuntivi saranno tenuti a mandare in crash il programma.

Alcuni compilatori potrebbero produrre codice che andrà in crash con solo un singolo byte sulla dimensione del buffer - è undefined ciò che il comportamento è

.

Credo che da 13 è sufficiente per sovrascrivere l'indirizzo di ritorno, o qualcosa di simile, che si blocca quando le vostre dichiarazioni di funzione. Ma un altro compilatore o un'altra piattaforma potrebbe / si bloccherà con una lunghezza diversa.

Anche il programma potrebbe bloccarsi con una lunghezza diversa, se ha funzionato per un tempo più lungo, se era stato sovrascritto qualcosa di meno importante.

Per la piattaforma Intel a 32 bit la spiegazione è la seguente. Quando si dichiara char [5] sulla pila il compilatore alloca realmente 8 byte a causa di allineamento. Poi è tipico per le funzioni di avere il seguente prologo:

push ebp
mov ebp, esp

questo consente di risparmiare valore del Registro di EBP sulla pila, poi si sposta registro ESP valore nel EBP per l'utilizzo di esp valore per accedere ai parametri. Questo porta a più 4 byte sulla pila da occupare con valore EBP.

Nel ebp epilogo viene ripristinato, ma il suo valore è solitamente utilizzato solo per l'accesso ai parametri funzionali stack allocato, quindi sovrascrivendo non può ferire nella maggioranza dei casi.

In modo da avere il seguente schema (stack cresce verso il basso su Intel):. 8 byte per l'array, quindi 4 byte per EBP, poi di solito l'indirizzo di ritorno

Questo è il motivo per cui è necessario sovrascrivere almeno 13 byte di crash del programma.

Per aggiungere alle risposte di cui sopra: è possibile verificare per i bug come questi con uno strumento come Valgrind . Se siete su Windows, dare un'occhiata a questo SO filo .

Dipende da ciò che è in pila dopo la matrice "str". Basta capita di non essere calpestare qualsiasi cosa critica fino a quando si copia che molti caratteri.

Quindi sta andando a dipendere da ciò che il resto è nella funzione, il compilatore utilizzato e, eventualmente, le opzioni del compilatore troppo.

13 è 5 + 8, suggerendo ci sono due parole non critiche dopo l'array str, quindi qualcosa di critico (forse l'indirizzo di ritorno)

Questa è la bellezza pura di comportamento non definito (UB): è undefined

.

Il tuo codice:

char str[5];
strcpy(str,"Hello12345678");

Scrive 14 byte / caratteri da str che può contenere solo 5 byte / caratteri. Questo richiama UB.

D:. Allora, perché non si blocca per "Hello1234567" e solo crash per "Hello12345678", cioè di stringa con lunghezza di 13 o più di 13

  

Poiché il comportamento non è definito.   Utilizzare strncpy. Vedere questa pagina    http://en.wikipedia.org/wiki/Strcpy   per ulteriori informazioni.

strncpy è pericoloso in quanto non aggiunge una terminazione NULL se la stringa di origine ha una lunghezza> = n dove n è la dimensione della stringa di destinazione.

char s[5];
strncpy(s,5,"test12345");
printf("%s",s); // crash

Usiamo sempre strlcpy per alleviare questo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top