2009-08-16 19 views
19

Ho visto l'uso di questo modello per concatenare su una stringa in qualche codice su cui stavo lavorando:Sprintf (buffer, "% s [...]", buffer, [...]) è sicuro?

sprintf(buffer, "%s <input type='file' name='%s' />\r\n", buffer, id); 
sprintf(buffer, "%s</td>", buffer); 

e sono abbastanza certo che non è sicura C. Si noterà che buffer è sia l'output e il primo input.

A parte l'ovvia possibilità di un buffer overflow, credo non ci sia alcuna garanzia che il buffer non venga modificato tra l'inizio e la fine della funzione (cioè, non vi è alcuna garanzia su quale sia lo stato del buffer sarà durante l'esecuzione della funzione). La firma di sprintf specifica inoltre che la stringa di destinazione è restrict ed.

Ricordo anche un rapporto di speculative writing in memcpy e non vedo alcun motivo per cui una libreria C potrebbe fare la stessa cosa in uno sprintf. In questo caso, ovviamente, scriverebbe alla sua fonte. Quindi questo comportamento è sicuro?

FYI, ho proposto:

char *bufEnd = buffer + strlen(buffer); 
/* sprintf returns the number of f'd and print'd into the s */ 
bufEnd += sprintf(bufEnd, " <input type='file' name='%s' />\r\n", id); 

per sostituire questo.

+0

Anche se è * sicuro * (non si blocca, ecc.), Posso immaginare che generi un risultato diverso da quello previsto. –

+0

@AndrewMedico Come va? – cat

risposta

18

Dal glibc sprintf() documentation:

Il comportamento di questa funzione è indefinito se la copia avviene tra oggetti che si sovrappongono-per esempio, se s è data anche come argomento da stampare sotto controllo della conversione '% s'.

Può essere sicuro in una particolare implementazione; ma non potevi contare sul fatto che fosse portatile.

Non sono sicuro che la vostra proposta sia sicura in tutti i casi. Potresti ancora sovrapporre i buffer. È tardi e mia moglie mi sta buggin ma penso che potresti ancora avere il caso in cui vuoi usare di nuovo la stringa originale nella stringa concatenata e stai sovrascrivendo il carattere null e quindi l'implementazione dello sprintf potrebbe non sapere dove è stata riutilizzata stringa finisce.

Si potrebbe semplicemente voler attaccare con un snprint() a un buffer temporaneo, quindi strncat() sul buffer originale.

+1

Ok, volevo solo un controllo di sanità mentale. [POSIX dice la stessa cosa] (http://www.opengroup.org/onlinepubs/9699919799/functions/sprintf.html): > Se la copia avviene tra oggetti che si sovrappongono come risultato di una chiamata a sprintf() o snprintf(), i risultati non sono definiti. –

+0

In realtà, non sto sovrapponendo i buffer nella mia seconda: è un buffer strettamente diverso. Non uso l'originale. –

+0

A meno che tu non stia vedendo qualcosa che io non, che è del tutto possibile. –

4

In questo caso specifico, funzionerà perché la stringa in buffer sarà la prima cosa che verrà inserita in buffer (di nuovo, inutile), quindi è necessario utilizzare strcat() per ottenere lo stesso [quasi] effetto.

Ma, se si sta cercando di combinare strcat() con le possibilità di formattazione di sprintf(), si può provare questo:

sprintf(&buffer[strlen(buffer)], " <input type='file' name='%s' />\r\n", id);
3

Se si desidera concatenare testo formattato alla fine di un buffer utilizzando printf(), Ti consigliamo di utilizzare un numero intero per tenere traccia della posizione finale.

int i = strlen(buffer); 
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id); 
i += sprintf(&buffer[i], "</td>"); 

o:

int i = strlen(buffer); 
i += sprintf(&buffer[i], " <input type='file' name='%s' />\r\n", id); 
strcat(&buffer[i], "</td>"); 

E prima che la gente va berserk downvoting questo ("Questo non è sicuro è possibile sovraccarico del buffer!"), Sto solo affrontando un modo ragionevole per costruire una stringa formattata in C/C++.

+0

Penso che il tuo suggerimento sia funzionalmente uguale al mio sostituto proposto, ma usando una notazione leggermente diversa. Posso capire perché alcuni potrebbero preferire vederlo scritto in questo modo, però. –