2009-06-01 12 views
5

quando cerco di fare le cose in questo modo:Perché MSVC++ considera "std :: strcat" non "sicuro"? (C++)

char* prefix = "Sector_Data\\sector"; 
char* s_num = "0"; 
std::strcat(prefix, s_num); 
std::strcat(prefix, "\\"); 

e così via e così via, ho ricevuto un avviso

warning C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. 

Perché strcat considerate non sicure, e c'è un modo sbarazzarsi di questo avviso senza usare strcat_s?

Inoltre, se l'unico modo per eliminare l'avviso è utilizzare strcat_s, come funziona (sintassi: apparentemente non ci vogliono due argomenti).

+13

dovresti sapere che il tuo esempio è orribilmente sbagliato. Le costanti stringa (come ad esempio: char * s = "hello";) NON sono scrivibili. Se sei fortunato, si bloccherà, se sei sfortunato farà in modo che l'applicazione si comporti in modo non corretto in qualche modo sottile. il modo corretto per eseguire ciò che si desidera è il seguente: prefisso char [SIZE] = "Sector_Data \\ sector"; dove SIZE è abbastanza grande da contenere il prefisso E qualunque cosa si intenda aggiungervi. –

+3

Come scritto, l'esempio contiene un buffer overflow. Non solo un possibile overflow del buffer, ma un certo. –

risposta

26

Poiché il buffer, prefisso, potrebbe avere meno spazio di quello che si sta copiando, causando un sovraccarico del buffer. Pertanto, un hacker può passare in una stringa appositamente predisposta che sovrascrive l'indirizzo di ritorno o un'altra memoria critica e avvia l'esecuzione del codice nel contesto del programma.

strcat_s risolve questo costringendo a passare la lunghezza del buffer in cui si sta copiando la stringa; troncherà la stringa se necessario per assicurarsi che il buffer non sia sovraccaricato.

google strcat_s per vedere esattamente come usarlo.

+1

strcat_s è una versione di una libreria di funzioni come parte dei miglioramenti di sicurezza per CRT - http://msdn.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx – Sean

+3

questo è semplicemente un problema di paura per conto di Microsoft per assicurarsi che il codice che scrivi non possa essere compilato da nessuna parte ma su Windows.'strcat_s'è nient'altro che un' strncat' proprietario (che esiste da 40 anni). Inoltre, 'strcat' non è pericoloso in quanto tale, in primo luogo, né chiama' strcat_s' con la lunghezza fornita da 'strlen 'alcun più sicuro. Ciò che non è sicuro accetta ciecamente input arbitrari (e arbitrari), ma l'uso di una funzione non standard non risolve questo problema, ma si bloccherà solo in una funzione diversa ('strlen'). – Damon

+1

@DeadMG: È vero che l'uso di 'strcat_s' significa che non è necessario sottrarre la lunghezza iniziale dalla dimensione totale, ma a parte questo è esattamente la stessa, tranne che non è standard e non portabile. Ma il mio punto in generale è che l'uso di funzioni "sicure" non rende affatto più sicuro. O sai che puoi fidarti di alcuni dati (come le stringhe letterali nel tuo programma) o sai di non fidarti (dati inseriti dall'utente), e in ogni caso devi conoscere le dimensioni del buffer di destinazione. Se questo non è il caso, tutto è perduto, indipendentemente dalle funzioni "sicure" che si usano. Lo stesso vale per strncat, ... – Damon

3

Perché non ha alcun mezzo di controllo per vedere se la stringa di destinazione (prefisso) nel tuo caso sarà scritta oltre i suoi limiti. strcat funziona essenzialmente in looping, copiando byte per byte la stringa sorgente nella destinazione. Si ferma quando vede un valore "0" (indicato da '\ 0') chiamato terminale nulla. Poiché C non ha un controllo dei limiti incorporati, e il dest str è solo un posto in memoria, strcat continuerà ad andare ad-infinidium anche se esplode oltre lo str sorgente o il dest. str non ha un terminale nulla.

Le soluzioni di cui sopra sono specifiche della piattaforma per l'ambiente Windows. Se volete qualcosa di indipendente della piattaforma, si deve disputare con strncat:

strncat(char* dest, const char* src, size_t count) 

Questa è un'altra opzione quando viene utilizzato in modo intelligente. È possibile utilizzare il conteggio per specificare il numero massimo di caratteri da copiare. Per fare questo, devi capire quanto spazio è disponibile in dest (quanto hai assegnato - strlen (dest)) e passarlo come conteggio.

+1

Anche strncat non è sicuro. Da MSDN: strncat non controlla lo spazio sufficiente in strDest; è quindi una potenziale causa di sovraccarichi del buffer. Tieni presente che il conteggio limita il numero di caratteri aggiunti; non è un limite alle dimensioni di strDest. Vedi l'esempio qui sotto. Per ulteriori informazioni, vedere Evitare sovraccarichi del buffer. –

+0

Il controllo dello spazio sufficiente nel buffer di destinazione non rientra nell'ambito della lingua e richiede funzioni aggiuntive dal sistema operativo/dal compilatore. –

+2

MSDN non ha senso su strncat(). Costringe il programmatore ad entrare in una dimensione, e due dimensioni possono essere sbagliate altrettanto facilmente di una. Il problema con strncat(), come strncpy(), è che non fa la stessa cosa di strcat() (o strcpy()) di lunghezza limitata. –

4

Questa è una delle funzioni di manipolazione delle stringhe in C/C++ che può causare errori di sovraccarico del buffer.

Il problema è che la funzione non sa quale sia la dimensione dei buffer. Dalla documentazione MSDN:

Il primo argomento, strDestination, deve essere abbastanza grande da contenere il strDestination attuale e strSource combinato e una chiusura '\ 0'; altrimenti si può verificare un sovraccarico del buffer.

strcat_s richiede un argomento aggiuntivo che indica la dimensione del buffer. Questo gli permette di convalidare le dimensioni prima di concat e previene i sovraccarichi. Vedi http://msdn.microsoft.com/en-us/library/d45bbxx4.aspx

+0

+1 Per fornire il collegamento alla documentazione effettiva. – Eclipse

+0

Ora se l'argomento per 'strcat_s' è stato controllato anche per la correttezza dal compilatore, o il comportamento di' strcat_s' era affidabile per errore, ... Sfortunatamente, non è il caso, quindi è un esercizio di futilità. – Deduplicator

28

Se si utilizza C++, perché non evitare l'intero caos e utilizzare std::string.Lo stesso esempio senza errori sarebbe simile al seguente:

std::string prefix = "Sector_Data\\sector"; 
prefix += "0"; 
prefix += "\\" 

non c'è bisogno di preoccuparsi delle dimensioni del buffer e di tutte queste cose. E se hai un'API che prende uno const char *, puoi semplicemente usare il membro .c_str();

some_c_api(prefix.c_str()); 
+4

Bello vedere una buona risposta al problema di fondo. Avrei votato più volte se potessi. –

4

Si può sbarazzarsi di questi avvertimento, aggiungendo:

_CRT_SECURE_NO_WARNINGS 

e

_SCL_SECURE_NO_WARNINGS 

di definizioni del preprocessore del vostro progetto.

+0

Sì, la soppressione del messaggio di avviso usando la bandiera sopra è la scelta migliore se si vuole scrivere codice portatile. l'utilizzo di strcat_s può portare a codice non portabile poiché questo è specifico per il compilatore Microsoft. –

0

Ci sono due problemi con strcat. In primo luogo, si deve fare tutto il vostro convalida di fuori della funzione, fare il lavoro che è quasi la stessa della funzione di:

if(pDest+strlen(pDest)+strlen(pScr) < destSize) 

Bisogna camminare per tutta la lunghezza di entrambe le stringhe solo per assicurarsi che si adatta, prima di percorrere tutta la loro lunghezza ANCORA per fare la copia. Per questo motivo, molti programmatori presumeranno semplicemente che si adatti e salti il ​​test. Ancora peggio, potrebbe essere che quando il codice viene scritto per la prima volta è GARANTITO essere adatto, ma quando qualcuno aggiunge un altro strcat o cambia una dimensione del buffer o una costante da qualche altra parte nel programma, ora avete problemi.

L'altro problema è se pSrc e pDst si sovrappongono. A seconda del compilatore, strcat può benissimo essere un semplice ciclo che controlla un carattere alla volta per uno 0 in pSrc. Se pDst sovrascrive quello 0, allora entrerai in un ciclo che verrà eseguito fino a quando il tuo programma si blocca.

4

Per disattivare l'avviso, è possibile farlo.

#pragma warning(disable:4996) 

btw, si consiglia vivamente di utilizzare strcat_s().

Problemi correlati