Неизвестная причина SIGSEGV в многопоточном клиент-серверном чат-приложении C - PullRequest
0 голосов
/ 09 ноября 2011

Я учусь на третьем курсе по специальности «Разработка программного обеспечения» и прохожу курс «Операционные системы».

Я работал над приложением чата клиент-сервер в C, используя pthreads и сокеты. Я пытался использовать pthreads для обеспечения параллелизма обработки клиента без необходимости разветвления. (Если это имеет значение, я разрабатываю на Ubuntu 11.04 x86).

Вместо того, чтобы хранить все как статические или глобальные / локальные переменные, я создал два структурированных типа данных, serverInfo_t и clientInfo_t, которые хранят мьютекс, дескрипторы файлов, флаг подключения и другую подобную информацию. Список клиентов реализован в виде простого односвязного списка, хранящегося в serverInfo_t, который блокируется и разблокируется во время изменений.

При запуске серверного приложения я сначала вызываю createServer(), который устанавливает сервер и, в конце концов, запускает дочерний поток, в обязанности которого входит прослушивание новых соединений. Эта функция возвращает указатель на недавно выделенный экземпляр serverInfo_t, который затем передается в вызов createClient(serverInfo_t* pServer, int out_fd) для создания клиента «admin», что позволяет использовать сервер как клиент сам по себе. Вот где у меня проблема, так как кажется, что она производит segfault, как только он вызывает createClient(). (Ниже приведен некоторый урезанный код:)

int main(int argc, char** argv)
{
    // ...
    // Get listenPort from argv[1].

    // Initialize the server.
    serverInfo_t* pServer = createServer(listenPort);

    // If createServer() failed, exit.
    if (!pServer) {
        fatal_error("ERROR: Unable to create server!"); // exit program
    }

    // Create and register the admin client.
    clientInfo_t* pAdmin = createClient(pServer, STDOUT_FILENO); // Outputs directly to stdout

    // ...
}

При отладке программы с помощью gdb я шел по main () и заметил несколько интересных выводов:

(gdb) n
22      serverInfo_t* pServer = createServer(listenPort);
(gdb) n
[New Thread 0xb7e53b70 (LWP 7986)]
25      if (!pServer) {
(gdb) n
30      clientInfo_t* pAdmin = createClient(pServer, FD_STDOUT);
(gdb) n
server4: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *)
&((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) &&
old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof
(struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 *
(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end &
pagemask) == 0)' failed.

Program received signal SIGABRT, Aborted.
0xb7fe1424 in __kernel_vsyscall ()
(gdb) n
Single stepping until exit from function __kernel_vsyscall,
which has no line number information.
[Thread 0xb7e53b70 (LWP 7986) exited]

Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
(gdb)

Что здесь происходит? Мне кажется, что программа полностью пропустила вызов createServer (), хотя проверка на NULL прошла. GDB отказался входить в функцию createServer (), или это было просто обойдено из-за какой-то проблемы оптимизации компилятора? Если это так, то что с выводом [New Thread 0xb7e53b70 (LWP 7986)]? И что на земле вызывает несостоятельное утверждение в malloc.c?

Буду признателен за любую помощь в этом вопросе, которую вы можете оказать. Пожалуйста, дайте мне знать, если есть проблема с моей методологией или с информацией, которую я предоставил. Я готов опубликовать мой полный Makefile и исходный код, если это необходимо, хотя для запуска make-файла необходима некоторая модификация (т.е. изменение переменной $ (OUTDIR) файла Makefile).

РЕДАКТИРОВАТЬ: Я думаю, я нашел причину проблемы.

В createClient():

// ...
clientInfo_t* client = (clientInfo_t*)malloc(sizeof(clientInfo_t*)); // Accidental typo.

Исправлено:

// ...
clientInfo_t* client = (clientInfo_t*)malloc(sizeof(clientInfo_t)); 

Да, это исправило. Прошу прощения за потерю времени, но спасибо всем за помощь.

Ответы [ 2 ]

5 голосов
/ 09 ноября 2011

Это похоже на ошибку памяти. Попробуйте запустить его через valgrind: valgind --tool=memcheck [COMMAND]

Для получения дополнительной информации перейдите на сайт Valgrind .

4 голосов
/ 09 ноября 2011

Что здесь происходит?

Это:

malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) ...

является классической сигнатурой повреждения кучи (double free(), запись после конца malloc() ed блока и т. д.).

Инструмент для поиска таких ошибок в Linux - Valgrind .Используйте его часто, это сэкономит вам бесчисленные часы отладки.

...