2011-06-27 26 views
8

Niektóre narzędzia statycznego analizatora kodu sugerują, że wszystkie funkcje strcat powinny zostać zastąpione przez strncat dla celów bezpieczeństwa?strcat Vs strncat - Kiedy należy używać której funkcji?

W programie, jeśli dokładnie wiemy rozmiar bufora docelowego i buforów źródłowych, czy nadal zaleca się stosowanie strncat?

Co więcej, biorąc pod uwagę sugestie narzędzi statycznych, należy użyć polecenia strcat?

Odpowiedz

10

Jeśli masz absolutną pewność co do rozmiaru bufora źródłowego i że bufor źródłowy zawiera znak NULL, kończący łańcuch, możesz bezpiecznie użyć strcat, gdy bufor docelowy jest wystarczająco duży.

Nadal zalecamy użycie strncat i nadać jej rozmiar bufora docelowego - długość łańcucha docelowego - 1

Uwaga: I edycja tego ponieważ komentarze zauważyć, że moja poprzednia odpowiedź była strasznie źle.

+0

+1. Podkreślam, że w niektórych systemach (np. BSD) kompilator ostrzega, jeśli używasz "wielkości-ogólnych" funkcji manipulowania ciągami znaków (strcat, strcpy, itp.). – dave

+1

Myślę, że masz na myśli "... daj mu rozmiar bufora docelowego _minus rozmiar łańcucha, który już zawiera. " – Nemo

+3

Ta odpowiedź jest niebezpiecznie błędna. @Nemo podszedł bliżej, ale myślę, że wciąż jest jeden. [Odpowiedź Pankaj] (http://stackoverflow.com/a/6502352/228539) wydaje się dokładna i jest bardzo szczegółowa. Musi to być "rozmiar bufora docelowego - długość ciągu docelowego - 1", aby odpowiednio uniknąć przepełnień bufora. Chociaż wydaje się to głupim wyborem przy projektowaniu tej funkcji, ponieważ musi ona z natury szukać terminatora zerowego przed rozpoczęciem kopiowania w każdym razie i może obliczyć długość wzdłuż drogi, abyśmy nie musieli robić tego dwa razy. – altendky

1

Nie robią tego samego, więc nie można ich zastąpić. Oba mają różne modele danych.

  • Łańcuch dla strcat jest zerowy zakończony ciąg, dla którego (jako programista) gwarantuje, że ma wystarczająco dużo miejsca.
  • Łańcuch dla strncat jest sekwencją z char który jest albo rozwiązana na długości jesteś wskazując lub przez null wypowiedzenia, jeżeli jest powinien być krótszy niż długości.

Korzystanie z tych funkcji zależy od założeń, które możesz (lub chcesz) zrobić w odniesieniu do swoich danych.

0

Narzędzia statyczne są generalnie kiepskie w zrozumieniu okoliczności związanych z używaniem funkcji. Założę się, że większość z nich ostrzega po prostu o każdy napotkany strcat zamiast sprawdzać, czy dane przekazane do funkcji są deterministyczne czy nie. Jak już wspomniano, jeśli masz kontrolę nad swoimi danymi wejściowymi, żadna funkcja nie jest niebezpieczna.

Należy jednak zauważyć, że strncat() jest nieco wolniejsza, ponieważ musi sprawdzić, czy termin "\ 0" i licznik, i jednoznacznie dodać go do końca. Natomiast strcat() po prostu sprawdza '\ 0', i dodaje końcowe '\ 0' do nowego łańcucha przez skopiowanie terminatora z drugiego ciągu wraz ze wszystkimi danymi.

11

Łącz dwa łańcuchy w jeden ciąg.

Prototypy

#include <string.h> 

char * strcat(char *restrict s1, const char *restrict s2); 

char * strncat(char *restrict s1, const char *restrict s2, size_t n); 

OPIS

strcat() i strncat() funkcji dołączenia kopię nul łańcucha S2 koniec przerwanego null ciąg s1, a następnie dodaj zakończenie \ 0 '. Ciąg s1 musi mieć wystarczającą ilość miejsca, aby pomieścić wynik.

Funkcja strncat() dodaje nie więcej niż n znaków z s2, a dodaje wtedy zakończenie \ 0 '.

Łańcuchy źródłowy i docelowy nie powinny się nakładać, ponieważ zachowanie jest nieokreślone jako zachowanie .

RETURN WARTOŚCI

The `strcat()` and `strncat()` functions return the pointer s1. 

względy bezpieczeństwa

Funkcja strcat() łatwo nadużywane w sposób, który pozwala szkodliwym użytkownikom dowolnie zmieniać program działający na funkcjonalność poprzez atak przepełnienia bufora.

Należy unikać używania strcat(). Zamiast tego należy użyć strncat() lub strlcat() i upewnić się, że żadne inne znaki nie są kopiowane do bufora docelowego, niż mogą być przechowywane.

Uwaga, że ​​strncat() może być również problematyczne. Może to być problem dotyczący bezpieczeństwa, aby ciąg był w ogóle obcięty. Ponieważ ścięty ciąg nie będzie tak długi, jak oryginał, może odnosić się do zupełnie innego zasobu, a użycie obciętego zasobu może spowodować nieprawidłowe zachowanie w postaci . Przykład:

void 
foo(const char *arbitrary_string) 
{ 
     char onstack[8] = ""; 

#if defined(BAD) 
     /* 
      * This first strcat is bad behavior. Do not use strcat! 
      */ 
     (void)strcat(onstack, arbitrary_string);  /* BAD! */ 
#elif defined(BETTER) 
     /* 
      * The following two lines demonstrate better use of 
      * strncat(). 
      */ 
     (void)strncat(onstack, arbitrary_string, 
      sizeof(onstack) - strlen(onstack) - 1); 
#elif defined(BEST) 
     /* 
      * These lines are even more robust due to testing for 
      * truncation. 
      */ 
     if (strlen(arbitrary_string) + 1 > 
      sizeof(onstack) - strlen(onstack)) 
       err(1, "onstack would be truncated"); 
     (void)strncat(onstack, arbitrary_string, 
      sizeof(onstack) - strlen(onstack) - 1); 
#endif 
} 

przykład

char dest[20] = "Hello"; 
char *src = ", World!"; 
char numbers[] = "12345678"; 

printf("dest before strcat: \"%s\"\n", dest); // "Hello" 

strcat(dest, src); 
printf("dest after strcat: \"%s\"\n", dest); // "Hello, World!" 

strncat(dest, numbers, 3); // strcat first 3 chars of numbers 
printf("dest after strncat: \"%s\"\n", dest); // "Hello, World!123" 
+0

Cześć, boczne komentarze nie odzwierciedlają faktycznego wyjścia programu, ponieważ src został zdefiniowany jako Świat (wielkie litery W) i świat wyjść (małe litery w). – Eduardo

+0

@Eduardo :) Dziękuję. Poprawione teraz. –

+0

"Funkcje strcat() i strncat() dołączają kopię końca skończonego łańcucha s2 na koniec" nie jest tak w przypadku "strncat()". 's2' nie musi być łańcuchem _ zakończonym znakiem __. Wystarczy, że 's2' będzie tablicą znaków, której brak może mieć _null character_. – chux

Powiązane problemy