it-swarm.it

Come sbarazzarsi di avvisi/errori "non sicuri" in Visual Studio (strcpy, sprintf, strdup)

Sto cercando di sbarazzarmi di alcuni avvertimenti del compilatore che dicono che strcpy, sprintf, ecc. Non sono sicuri. Capisco perché sono insicuri, ma non riesco a pensare a un buon modo per correggere il codice, in uno stile C++.

Ecco un estratto del codice:

extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName);                     // unsafe
// strncpy(extList->names[i],extName,length);          // also unsafe

Ecco il messaggio:

C4996: 'strcpy': questa funzione o variabile potrebbe essere Non sicura. Prendi in considerazione l'utilizzo di strcpy_s. Per disabilitare la deprecazione, utilizzare _CRT_SECURE_NO_WARNINGS. Vedi la guida in linea per i dettagli.

Non riesco a pensare a un modo sicuro per copiare i dati in C++ senza conoscere la lunghezza delle cose da copiare. So che c'è strlen (), ma non è sicuro dato che presuppone (forse erroneamente) che i dati sono terminati con null.

Anche:

// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);

C4996: 'sprintf': questa funzione o variabile potrebbe non essere sicura. Considera invece Usando sprintf_s. Per disabilitare la deprecazione, utilizzare _CRT_SECURE_NO_WARNINGS. Vedi la guida in linea per i dettagli.

Usare std :: string per concatenare è abbastanza facile, ma poi ho bisogno di ottenere i dati in extStr in qualche modo (e non usando strcpy, lol). La funzione string :: c_str () restituisce un puntatore a dati non modificabili, quindi non posso semplicemente impostare extStr uguale ad esso. (E non sono nemmeno sicuro che se il puntatore c_str () ha bisogno di eliminare lo chiama in seguito? Alloca lo spazio usando "nuovo"?)

Qualche consiglio su questa roba? Questo fa parte di un file di 10.000 righe che non è mio ... quindi non sono proprio entusiasta di riscrivere la cosa in modo C++.

21
Andre

Non hai davvero bisogno di pragmi per disabilitarli.

Per win32/msvc, in ProjectProperties -> Proprietà di configurazione -> C/C++ -> Preprocessore -> Definizioni del preprocessore, aggiungere le seguenti macro: 

_CRT_SECURE_NO_DEPRECATE  
_CRT_NONSTDC_NO_DEPRECATE

Oppure puoi passare questo nei parametri della riga di comando (-D_CRT_SECURE_NO_DEPRECATE). Probabilmente puoi # definirli all'inizio di certi file * .cpp. Inoltre, ci sono probabilmente più di loro (vedi crtdefs.h - sembra che ce ne siano molti ...). Questi tipi di avvertimenti normalmente ti dicono con quali macro puoi disabilitarli - basta leggere l'output del compilatore.

33
SigTerm

Ecco un'altra risposta a questa domanda.

#ifdef _MSC_VER
#pragma warning(Push)
#pragma warning(disable : 4996)
#endif

        strcpy(destination, source);

#ifdef _MSC_VER
#pragma warning(pop)
#endif
7
PapaAtHome

Se eliminare solo gli avvisi è il tuo obiettivo ... semplicemente definisci questo _CRT_SECURE_NO_WARNINGS e sopprimerà tutti gli avvisi di deprecazione. Ma questo non risolverà i problemi sottostanti con funzioni CRT non sicure. 

Se sei in versione visual studio> = 2005 e vuoi correggere questi avvertimenti in modo corretto ... il metodo più semplice è #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 e #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 nel tuo progetto. 

senza ulteriori modifiche al codice, è possibile osservare che la maggior parte degli avvisi vengono risolti automaticamente. Definendo questa finestra, verranno chiamate automaticamente le funzioni di sovraccarico sicure per la maggior parte delle funzioni CRT non sicure. Le dimensioni del buffer per gli array statici vengono calcolate automaticamente.

Sebbene i buffer allocati dinamicamente non vengano risolti in questo modo, è necessario correggerli manualmente. Si prega di fare riferimento questo link per ulteriori dettagli.

Di seguito è riportato un modo per correggere il tuo esempio in modo programmatico 

strcpy_s(extList->names[i], length, extName); 
6
V M Rakesh

Sai quanto copiare - hai assegnato spazio per questo!

Sicuramente non copieresti volentieri più dello spazio che hai assegnato? 

Preferirei utilizzare un metodo che eviti esplicitamente i sovraccarichi del buffer limitando il numero di elementi copiati. Di ritorno quando ero un programmatore C che usavamo 

dest = malloc(len);         // note: where did we get len?
if ( dest is null )  panic!  // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;

Questo è un po 'disordinato, ed è stato sottolineato che usa strncpy () un metodo che è stato originariamente progettato per i campi a larghezza fissa piuttosto che per le stringhe. Comunque fa male

Esistono metodi come strdup () e strlcpy () che possiamo aiutare.

I miei consigli:

1). Il tuo obiettivo non dovrebbe essere quello di sopprimere gli avvertimenti, ma per rendere il codice robusto.

2). Quando copi le stringhe devi assicurarti che:

  • Proteggiti da input errati, ad esempio una stringa non terminata o eccessivamente lunga.
  • Proteggiti dai guasti di malloc, 
  • Preferiamo fortemente le copie dei numeri contati di caratteri da copiare fino a quando non vediamo un valore nullo
  • Se pretendi di costruire una stringa, assicurati definitivamente che tu la interrompa

Se strlcpy () è disponibile nel tuo ambiente allora potresti usarlo, altrimenti perché non scrivere la tua piccola funzione di utilità? Quindi se ci sono avvertimenti solo in quella funzione che hai localizzato allora problema.

5
djna

Nel tuo primo esempio, conosci già la lunghezza. Dato che non stai allocando length+1 byte, suppongo che length INCLUDE il terminatore null. In tal caso, solo std::copy la stringa: std::copy(extName, extName + length, expList->names[i]);

Nel secondo esempio, supponendo che le stringhe di origine siano terminate con null, è possibile calcolare la lunghezza della stringa di destinazione e utilizzare nuovamente std::copy per concatenare manualmente, oppure è possibile utilizzare std::string e std::copy dai risultati di c_str nella destinazione (sempre supponendo di aver assegnato spazio sufficiente per esso).

c_str() non assegna memoria che richiederebbe la cancellazione esterna.

Infine nota che sizeof(char) sarà sempre uno e quindi è ridondante nel tuo malloc, anche se il numero di bit in quel personaggio potrebbe non essere 8 (Vedi CHAR_BIT).

4
Mark B

Penso che dovresti sostituire tutte le chiamate di funzione se possibile chiamare una tua implementazione. Un buon esempio qui sarebbe una funzione per sostituire strcpy e chiamare la versione specifica del compilatore di strcpy al suo interno. La tua implementazione può quindi essere facilmente modificata per adattarsi a qualsiasi compilatore di tua scelta, in particolare se vuoi aggiungere o modificare piattaforme/compilatori. 

Esempio:


char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
  return strcpy_s(Destination, Source, DestinationSize);
#else
  if(!(strlen(Source) >= DestinationSize))
     return strcpy(Destination, Source);
  else
     return 0x0;
#endif
}
2
Simon

Se la portabilità non è un problema, puoi usare 'strcpy_s' .

2
oefe

Se questo codice deve essere compilato solo per la piattaforma Windows, è meglio usare la versione protetta di queste funzioni. Tuttavia, se questo codice viene compilato su più piattaforme (linux, Aix ecc.), Allora puoi disabilitare l'avviso nel tuo file di configurazione del progetto di Windows (ad esempio, .vcxproj) utilizzando _CRT_SECURE_NO_WARNINGS oppure, puoi usare uno snippet di codice come questo in luoghi in cui tali funzioni sono state chiamate nel file .cpp.

#if _OS_ == _OS__WINDOWS
//secure function call
#else
//already written code
#endif
0

come suggerito nel messaggio, usa _CRT_SECURE_NO_WARNINGS per disabilitare questo avviso.

in ProjectProperties -> Proprietà di configurazione -> C/C++ -> Preprocessore -> Definizioni del preprocessore, aggiungere le seguenti macro:

_CRT_SECURE_NO_WARNINGS

0
cheng