2009-10-26 12 views
12

Ho fatto una funzione come questa:Esiste uno strcmp sicuro?

bool IsSameString(char* p1, char* p2) 
{ 
    return 0 == strcmp(p1, p2); 
} 

Il problema è che a volte, per errore, gli argomenti vengono passati che non sono stringhe (che significa che p1 o p2 non termina con un carattere nullo). Quindi, strcmp continua a eseguire il confronto finché non raggiunge la memoria non accessibile e si arresta in modo anomalo. Esiste una versione sicura di strcmp? O posso dire se p1 (e p2) è una stringa o non in modo sicuro?

+0

potrei avere mistakingly rimarcato la tua domanda a C. Siete alla ricerca di una soluzione C o C++? –

+0

Ricorda che anche lo strncmp non garantisce la sicurezza. –

+0

@Pavel Shved, c'è un tipo di ritorno bool, e C non ha il tipo bool, quindi penso che sia C++ –

risposta

16

No, non esiste un modo (standard) per stabilire se uno char * punta effettivamente alla memoria valida.

Nella propria situazione, è preferibile utilizzare std::string anziché char * s per tutte le stringhe, insieme all'operatore sovraccaricato ==. Se lo fai, il compilatore impone la sicurezza del tipo.

EDIT: Come per i commenti qui sotto se vi trovate in una situazione in cui a volte si passa char * s che possono o non possono essere stringhe valide per funzioni che prevedono stringhe null-terminated allora c'è qualcosa di fondamentalmente sbagliato con il tuo approccio , quindi in pratica la risposta @ janm in basso.

+3

..e se si utilizza std :: string, non è necessario scrivere una funzione come quella che hai scritto, risparmiando tempo ed energia. – JBRWilkinson

+3

L'utilizzo di std :: string non aiuta ancora se una delle stringhe viene alimentata come input da qualche parte. Alla fine della giornata, una std :: string deve essere istanziata da un char *. E se quel char * non punta a una stringa terminata da null, il costruttore std :: string esploderà o avrà un comportamento indefinito. L'unica soluzione * true * è quella di disinfettare le stringhe in qualche modo rispetto a una lunghezza massima (quando si costruiscono le istanze di std :: string se si va su quella rotta, o quando si usa strncmp invece di strcmp quando si va alla rotta char con terminazione nulla * –

+0

-1: proporsi per usare la "stringa" C++ per qualcuno che sta usando C non è proprio una risposta. "Il compilatore imporrebbe la sicurezza del tipo" ... Solo fino a quando qualcuno non fa i vecchi cast di stile C (per esempio "std :: string xxx = (char *) qualunque cosa"). Quello che potresti proporre è usare qualcosa di più complesso di "char *" per rappresentare le stringhe, ad esempio "struct mystr {uint32_t magicnum; ...}" dove "magicnum" deve avere un valore specifico, usare "std: string" non aiuta qui .. –

6

Non c'è cura per questo che è portatile. La convenzione afferma che c'è un carattere in più che contiene un carattere null che appartiene allo stesso blocco di memoria assegnato correttamente della stringa stessa. O si segue questa convenzione e si verifica qualsiasi comportamento fine o indefinito.

Se si conosce la lunghezza della stringa confrontata, è possibile utilizzare strncmp() ma non sarà di aiuto se la stringa passata al codice è effettivamente più breve della stringa confrontata.

13

In alcuni casi std::strncmp possibile risolvere il problema:

int strncmp (const char * str1, const char * str2, size_t num); 

Esso mette a confronto fino a num caratteri della stringa str1 C a quelli della stringa str2 C.


Inoltre, uno sguardo, quello che la divisione statunitense DHS National Cyber ​​Security recommends su questa materia:

Assicurarsi che le stringhe sono nulli terminati prima di passare in strcmp. Questo può essere fatto mettendo sempre un \ 0 nell'ultimo byte assegnato del buffer.

char str1[] ="something"; 
char str2[] = "another thing"; 
/* In this case we know strings are null terminated. Pretend we don't. */ 
str1[sizeof(str1)-1] = '\0'; 
str2[sizeof(str2)-1] = '\0'; 
/* Now the following is safe. */ 
if (strcmp(str1, str2)) { /* do something */ } else { /* do something else */ } 
+0

Se il sistema operativo è Linux, potrebbe De utile sapere che strncmp è incluso in LSB: http://dev.linuxfoundation.org/navigator/browse/int_single.php?cmd=list-by-name&Ilibrary=libc&Iname=strncmp –

1

Si può mettere un limite massimo al numero di caratteri da confrontare utilizzando la funzione strncmp.

+1

Ma non ha senso. Un 'strcmp (s1, s2)' non sembrerà più in 's1' di quanto non ci siano caratteri in' s2', e allo stesso tempo, devi confrontare l'intera lunghezza del più breve di essi .. quindi non c'è nessun modo che 'strncmp' possa aiutare. – u0b34a0f6ae

3

è possibile utilizzare strncmp, ma se possibile uso std :: string per evitare molti problemi :)

+0

std :: string può essere ancora vulnerabile se un'istanza è costruita su un char * che non è terminato con null. Ad un certo punto, per un codice sicuro vero o quasi vero, una lunghezza massima deve essere applicata in base al contesto (sia quando si usa strncmp, o durante l'istanziazione di std :: string.) –

-1

Tu non scrive, quale piattaforma che si sta utilizzando.Windows ha le seguenti funzioni:

IsBadStringPtr potrebbe essere quello che stai cercando, se si utilizza Windows.

+5

Le funzioni IsBadXXXPtr non sono generalmente un buona cosa da usare - a seconda di dove punta il puntatore, possono indurre crash casuali in altre parti del programma, ed è molto, molto più facile eseguire il debug di un crash vicino alla sua causa, invece di mezz'ora e sedici file sorgente. Vedi http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx per i dettagli. –

+0

Non solo, maschera altri problemi. Il puntatore potrebbe essere valido dal punto di vista del sistema operativo, ma la memoria potrebbe essere qualcos'altro (come un indirizzo sullo stack ...) – janm

+1

Oh, grazie per questi commenti. Ho avuto un'esperienza simile, ma ho contato questo per i problemi di casa. –

-1

Non c'è una risposta migliore a questo, come non è possibile verificare il char * è una stringa. L'unica soluzione è creare un tipo e usarlo come stringa per esempio str :: string o crearne uno proprio se si desidera qualcosa di più leggero. ie

struct MyString 
    { 
    MyString() : str(0), len(0) {} 
    MyString(char* x) { len = strlen(x); str = strdup(x); } 
    ⁓MyString() { if(str) free(str); } 
    char* str; 
    size_t len; 
    }; 

bool IsSameString(MyString& p1, MyString& p2) 
    { 
    return 0 == strcmp(p1.str, p2.str); 
    } 


MyString str1("test"); 
MyString str2("test"); 

if(IsSameString(str1, str2) {} 
+1

Cambia solo il punto di errore; se la memoria passata nel costruttore non è terminata con null, ci sarà comunque un errore. – janm

+0

"Vuoi qualcosa di più leggero" sembra essere la rovina. 'std :: string' farà tutto ciò che fa la tua classe, senza costi aggiuntivi. Luce! = Meno funzionalità. – GManNickG

+0

janm - Penso che sia un problema che non sarà in grado di risolvere senza utilizzare solo le stringhe statiche, ovvero "" da utilizzare e fare tutti gli altri usi di char * compile errori di tempo. –

9

Se si passano stringhe a strcmp() che non sono terminate con null si è già perso. Il fatto che tu abbia una stringa che non è terminata con null (ma dovrebbe essere) indica che hai problemi più profondi nel tuo codice. Non è possibile modificare strcmp() per risolvere questo problema in modo sicuro.

Si dovrebbe scrivere il codice in modo che non potrà mai accadere. Inizia usando la classe string. Ai confini in cui prendi i dati nel tuo codice, devi assicurarti di trattare i casi eccezionali; se ottieni troppi dati devi fare la cosa giusta. Ciò non significa esaurire la fine del tuo buffer. Se è necessario eseguire I/O in un buffer in stile C, utilizzare le funzioni in cui si specifica la lunghezza del buffer e rilevare e trattare i casi in cui il buffer non è sufficientemente grande in quel punto.

+3

Sì, cosa disse Janm. Quando trovi un bug, correggi il bug. Non cercare semplicemente di nasconderlo complicando altri codici in un futile tentativo di rendere meno severi i sintomi dell'insetto. In questo caso, c'è un errore nel codice che chiama IsSameString(). –

Problemi correlati