LINUX.ORG.RU

strcat, strcpy в потоках


0

0

Привет, есть проблема. есть сишная прога, что то типа #include <...> void* funk (void* ptr); int main(){ pthread_t tid; void* rc; pthread_create(&tid, NULL, funk, NULL); pthread_join(&tid, &rc); return 0; } void* funk (void* ptr){ char* s1 = "test_s1"; char* s2 = "test_s2"; strcat(s1, s2); } так вот, если ф-ция funk объявлена в другом файле, то на strcat происходит Segmentation fault, если в этом же, то все путем, в чем тут дело?

anonymous

Ты неправильно пользуешься strcat, поэтому она у тебя переписывает байты после s1, в которых может быть что угодно, например s2 или ещё что-нибудь, так что программа себя может вести как ей нравится. Классический buffer overflow :-)

justme
()

Да нет - дело не в этом. В большинстве случаев там будет s2, поэтому ничего страшного не случится, но это, конечно не значит, что нужно(можно) так делать. А вылетает в этом случае из-зи того, что строки объявлены как строковые литералы, которые по семантике языка C являются константами (const char *). Если объявлять, как
char c1[]=
char c2[]=,
то падать в кору не будет. Но, сдается мне , что человек просто ищет баги в glibc, иначе не делал бы две такие очевидные ошибки. Насчет того, что в одном случае вываливается, а в другом нет - чудеса какие-то, должно вываливаться в обоих случаях.

timur
()

1) Nikto tebe ne obeshaet chto posle c1 budet srazu c2. 2) nu prochitaite nakonec doki !!!!!

master
()

Конечно никто мне этого не обещает, поэтому я и написал "в большинстве случаев", а еще потом приписал, что так делать не стоит. Просто вылетает скорее всего не из-за buffer overflow. Если не поняли в чем тут дело, то вместо strcat(s1, s2) напишите s1[1] = 'a' - точно так-же вылетит. А все потому, что это строковый литерал. И потом - IMHO человек в курсе и про buffer overflow и про строки. IMHO его волнует, что вылетает не в обоих случаях :).

timur
()

Умм. Вместо s1[1] следует читать *(s1+1), потому, что в первом случае может компилер ругнуться.

timur
()

Pishu iz links'a, tak chto sorry za translit.
1. Ne overflow, tak ne overflow, ja ne nastaivaju...
2. s1[1] dolzhno byt' polnost'ju ekvivalentno *(s1 + 1), ty tochno uveren, chto kompil'ator rugaets'a tol'ko v odnom sluchae?
3. U menja vyvalivaets'a v core vo vseh sluchajah, dazhe esli pishu char s1[] = ... i nezavisimo ot togo, gde opredelena funkcija funk (). Tak chto undefined behavior jest' undefined behavior. (U menja debian/unstable, glibc-2.2).

justme
()

Прошу прощения за непроверенные данные - только что проверил и на VCPP, и на gcc. В обоих случаях не ругается ни на s1[1], ни на *(s1+1), хотя в обоих случаях легко можно определить, что модифицируются константы. Самое интересное, что пихают они эти строки все таки в readonly секцию - из-за этого и падает в кору. При объявлении строк, как s1[]=... - все нормально, как и должно быть - память writable. Если у тебя валится в strcat (bt посмотри), должно быть это overflow и есть :).

timur
()

У меня не валилось только в том очевидном случае, когда я написал char s1[] = "test"; s1[1] = 'a'; Иначе падало.
gcc (2.95.3 из debian/unstable), кстати, то, что записывается константа, обнаруживает и выдаёт warning.
bt пробовал, но gdb у меня сходит с ума, если в программе используются threads, так что не видно, в чём оно валится. Но с другой стороны, вроде ему кроме как в strcat больше валиться негде...

justme
()

Мужики, может я не прав, но: strcat(s1,s2) ДОБАВЛЯЕТ к строке s1 строку s2 через системный вызов, а s1 определена как статический массив (указатель на область памяти, выделенную при компилляции, как кто-то правильно заметил в сгенеренном ассемблер-коде). так что будет если добавить что-нить в область данных не доступную для записи? правильно - сегфалт! что и наблюдаем. вроде, очевидно?

stormbringer
()

Очевидно. Всё дело в том, что у человека одна программа валится, а другая, которая несущественно отличается, - нет. И ещё тут было некоторое несогласие по поводу того, считать это buffer overflow или нет.

justme
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.