Mam globalną strukturę:

struct thread_data{
   char *incall[10];
   int syscall arg_no;
   int client_socket;
};

I w głównym ()

char buffer[256];
char *incall[10];
struct thread_data arg_to_thread;

strcpy(incall[0],buffer);   /*works fine*/
strcpy(arg_to_thread.incall[0],buffer); /*causes segmentation fault*/

Dlaczego tak się dzieje i proszę zasugerować wyjście.

Dzięki

0
Lipika Deka 9 czerwiec 2011, 09:56
1
Gdzie alokujesz pamięć do przechowywania tych ciągów?
 – 
Mat
9 czerwiec 2011, 09:58
Czy nie będzie automatycznie przechowywany w stosie?
 – 
Lipika Deka
9 czerwiec 2011, 10:00
1
Nie, wszystko, co zostało przydzielone, to 10 wskaźników.
 – 
Mat
9 czerwiec 2011, 10:02

3 odpowiedzi

Najlepsza odpowiedź

Segfault oznacza, że ​​coś jest nie tak. Ale nie segfault nie oznacza, że ​​coś nie jest nie tak. Jeśli dwie sytuacje są w zasadzie takie same, a jedna jest segfault, a druga nie, zwykle oznacza to, że są obie błędne, ale tylko jedna z nich uruchamia segfault.

Patrząc na linię char* incall[10], oznacza to, że masz tablicę 10 wskaźników do znaku. Domyślnie te wskaźniki będą wskazywać losowe miejsca. Dlatego strcpying do incall[0] będzie kopiować ciąg do losowej lokalizacji. To najprawdopodobniej spowoduje segfault! Musisz najpierw zainicjować incall[0] (używając malloc).

Więc ważniejsze pytanie brzmi: dlaczego nie jest segfault w pierwszej linii? Wyobrażam sobie, że powodem jest to, że tak się składa, że to, co było wcześniej w pamięci, było prawidłowym wskaźnikiem. Dlatego strcpy nie segfault, po prostu nadpisuje coś innego, co później spowoduje całkowicie nieoczekiwane zachowanie. Musisz więc poprawić oba wiersze kodu.

Innym problemem (gdy już to naprawisz) jest to, że strcpy sam w sobie jest bardzo niebezpieczny — ponieważ kopiuje ciągi, aż znajdzie 0 bajtów, a następnie się zatrzyma, nigdy nie możesz być pewien, ile dokładnie skopiować (chyba że używasz strlen do przydzielenia pamięci docelowej). Dlatego powinieneś zamiast tego użyć strncpy, aby ograniczyć liczbę kopiowanych bajtów do rozmiaru bufora.

5
Jonathan Leffler 9 czerwiec 2011, 10:23
1
'Ostrożny'? Być może miałeś na myśli „podejrzany” lub „niebezpieczny” lub… Jeśli użył go ktoś, kto wie, co robi (co oznacza między innymi, jak długi jest ciąg źródłowy i ile jest miejsca w buforze docelowym) , strcpy() jest całkowicie bezpieczny. Nie wszyscy zapewniają, że są bezpieczni. (Istnieje argument, że jeśli wiesz, jak długie są łańcuchy, możesz użyć memmove(), a czasem memcpy(), aby wykonać kopiowanie łańcucha wydajniej.) Pamiętaj, że strncpy() nie gwarantuje zerowego zakończenia Twoich ciągów. (Korzystanie z strncat() jest jeszcze bardziej niebezpieczne!)
 – 
Jonathan Leffler
9 czerwiec 2011, 10:07
Leffler To prawda, ale doradzam komuś, kto nie wie, co robi (a powiedziałem „chyba że używasz strlenu do alokacji pamięci docelowej”). Ale to jest bardzo dobry punkt w strncpy -- nie jestem pewien, co jest gorsze: nadpisanie bufora, czy posiadanie łańcucha niezakończonego znakiem NULL. (Nadal powiedziałbym, że to pierwsze jest gorsze, więc wolę strncpy od strcpy.)
 – 
mgiuca
9 czerwiec 2011, 10:13
1
To trudne. Standardowe funkcje napisów w języku C pozostawiają wiele do życzenia (ale są standardowe, powszechnie dostępne i można z nich bezpiecznie korzystać). Brak zakończenia zerowego w krótkiej kopii jest tak poważny, że inne korzyści z strncpy() są, IMNSHO, przewyższane przez złe zachowanie w jednym przypadku, w którym naprawdę potrzebujesz tego, aby zachowywać się rozsądnie. Żyłbym z zerowym wypełnieniem, gdyby gwarantowało zerowe zakończenie. W swoim pierwotnym zastosowaniu nie zerowe zakończenie było pozytywną cnotą, ale to już historia starożytna. (Zaprojektowano go do kopiowania 14-znakowych nazw plików w katalogach w systemie Unix.)
 – 
Jonathan Leffler
9 czerwiec 2011, 10:22

Nie zainicjalizowałeś wskaźnika incall[0], więc Bóg wie tylko, dokąd pisze pierwszy strcpy(). Masz pecha, że ​​Twój program nie zawiesza się od razu.

Nie zainicjalizowałeś wskaźnika arg_to_thread.incall[0], więc Bóg wie tylko, dokąd pisze drugi strcpy(). Masz szczęście, że Twój program ulega awarii teraz, a nie później.

W żadnym wypadku nie jest to wina kompilatora; musisz zawsze upewnić się, że zainicjujesz swoje wskaźniki.

1
Jonathan Leffler 9 czerwiec 2011, 10:16
  1. Upewnij się, że masz wystarczająco dużo pamięci przydzielonej dla buforów łańcuchowych.
  2. Trzymaj się z dala od strcpy. Zamiast tego użyj strncpy. strcpy jest znanym źródłem luk w zabezpieczeniach związanych z przepełnieniem bufora - koszmarem bezpieczeństwa i konserwacji, dla którego tak naprawdę nie ma usprawiedliwienia.
0
tdammers 9 czerwiec 2011, 10:01
1
Pamiętaj, że strncpy() nie gwarantuje zerowego zakończenia twoich łańcuchów, jeśli źródło jest zbyt długie. Gwarantuje również wypełnienie pustego ciągu, jeśli źródło jest krótsze niż miejsce docelowe. (Użycie strncat() jest jeszcze bardziej ryzykowne! Jaki rozmiar określasz w parametrze długości? Odpowiedź nie jest wielkością ciągu docelowego!)
 – 
Jonathan Leffler
9 czerwiec 2011, 10:12
Chodzi mi o to, że poleganie wyłącznie na strażniku przy określaniu długości struny jest kruche. Jawne przenoszenie długości ciągów nie jest możliwe, chociaż oczywiście nadal możesz tworzyć błędy.
 – 
tdammers
9 czerwiec 2011, 10:17