#c #sockets #udp #malloc #fopen
#c #сокеты #udp #malloc #fopen
Вопрос:
Я пробовал использовать GDB и Valgrind, но, похоже, не могу точно определить проблему. Интересно, что программа вылетает при обычном выполнении и GDB, но не Valgrid.
Чтобы помочь вам разобраться в коде, вот основная идея программы: связь с сервером через сокеты и UDP для передачи файла и обработка некоторой базовой потери пакетов.
Я не буду делиться кодом сервера, потому что знаю, что проблемы нет. Момент, который может кого-то смутить, заключается в том, что я сам реализую потерю пакетов с помощью генератора чисел. Прямо сейчас он ничего не делает, кроме того, что заставляет программу использовать другой recvfrom.
Чтобы провести вас через вывод программы, клиент сообщает серверу, какой файл он хочет, сервер сообщает клиенту, какой размер файла он собирается отправить, а затем отправляет его порциями (по 10 символов за раз).
Вывод показывает, какой фрагмент отправлен, сколько символов было получено и какова объединенная строка.
Насколько я могу судить, передача файла выполнена успешно, это просто вызов fopen, который я использую для записи полученного файла, который доставляет мне проблемы. Не уверен, связано ли это с моим вызовом malloc или нет.
Вот исходный код:
pastebin.com/Z79hvw6L
Вот результаты выполнения CLI и Valgrind (GDB, похоже, не дает дополнительной информации):
Обратите внимание, что CLI выдает ошибку повреждения памяти malloc, а Valgrind — нет.
CLI: http://pastebin.com/qdTKMCD2
VALGRIND: http://pastebin.com/8inRygnU
Спасибо за любую помощь!
Добавлены результаты обратной трассировки GDB
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6( 0x6b961)[0x19a961]
/lib/i386-linux-gnu/libc.so.6( 0x6e15d)[0x19d15d]
/lib/i386-linux-gnu/libc.so.6(__libc_malloc 0x63)[0x19ef53]
/lib/i386-linux-gnu/libc.so.6( 0x5c2b8)[0x18b2b8]
/lib/i386-linux-gnu/libc.so.6(fopen 0x2c)[0x18b38c]
/home/---/client[0x8048dc2]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main 0xe7)[0x145e37]
/home/---/client[0x8048871]
Может быть, это может дать кому-то представление о том, в какой части программы ошибка?
Комментарии:
1. В общем, если вы не можете опубликовать соответствующее исходное подмножество в контексте своего сообщения, вы не получите много ответов.
2. Почему бы вам не опубликовать обратную трассировку того, где происходит сбой в valgrind? Бьюсь об заклад, что если вы получите эту обратную трассировку, а затем установите контрольную точку памяти для поврежденной памяти (точка сбоя), это приведет вас к вашей проблеме.
3. Что ты имеешь в виду, Джо? В какой области, я думаю, проблема?
4. @dbeer, если я не неправильно интерпретирую вывод valgrind, он вообще не падает в valgrind?
5. добавлена обратная трассировка. Я наблюдал за своей строкой, содержащей все фрагменты, и, похоже, все в порядке. Именно при открытии происходит сбой.
Ответ №1:
char chunk[10];
chunk[10] = '';
неверно, фрагмент [10] находится за массивом.
И вообще, будьте осторожны с этим
char filename[25];
scanf("%s",filename);
Если вы введете длинное имя файла, вы уничтожите память. использование fgets() было бы лучше. Вы также, по крайней мере, хотели бы проверить, успешно ли выполняется scanf, иначе следующий strlen() для filename недействителен.
строка 93 buf[strlen(buf)-1]='';
опасна, вы не можете использовать strlen, если буфер еще не завершен nul, и вы удаляете память, если buf является пустой строкой, поскольку вы индексируете buf[-1] .
Редактировать. Ваша другая проблема заключается strcat(fullstring,chunk);
в том, что у вас нет контроля в вашем цикле, который прекращает добавление к этой строке, если вы получаете больше данных, чем он может вместить. Размер также, вероятно, уменьшен на единицу, так как вам нужно место для последнего нулевого терминатора. Сделайте это, по крайней мере char * fullstring = malloc(sizeof(char)*filesize 1 );
, но вашему циклу действительно нужно проверить, что он не записывает дальше конца этого буфера.
Что касается добавления нулевого терминатора в buf
, вызов recv возвращает, сколько байтов вы прочитали, поэтому, если вы проверили recv на наличие ошибок, сделайте buf[numbytes] = 0
, но это также будет отключено на единицу, так как вы выделили 10 байт для buf
и пытаетесь прочитать в него 10 байт, нов C строке также требуется место для нулевого терминатора. Увеличьте размер буфера на 11 байт. Или recv() всего 9 байт.
На самом деле, вы ошибаетесь на одно много мест, поэтому начните подсчитывать, сколько байтов вам нужно, и были ли вы помещены в них. Помните, что в C массивы начинаются с нулевого индекса, а массив из 10 может быть проиндексирован только с индексом от 0 до 9.
Комментарии:
1. изменен бит фрагмента [10], но результатов нет. Я оставляю имя файла как есть, как только у меня все заработает, я проведу проверку ошибок. если я знаю, что buf не будет иметь нулевого завершения, как я могу добавить к нему нулевой терминатор без strlen?
2. Спасибо, ответ заключался в том, что я выходил за пределы полной строки и фрагмента. Мне пришлось увеличить полную строку, как вы предложили, и null завершает каждый фрагмент должным образом. Я рассмотрю другие проблемы.
Ответ №2:
Это (строка 93) вызывает подозрение:
buf[strlen(buf)-1]='';
ОБНОВИТЬ это (строка 99,100) также неверно:
char chunk[10];
chunk[10] = '';
UPDATE2: буфер слишком мал
char * fullstring = malloc(sizeof(char)*filesize); // line 103
...
strcat(fullstring,chunk); // line 124
ОБНОВЛЕНИЕ3:
UDP ненадежен. Передача пакета может завершиться ошибкой (пакеты могут быть отброшены в любом месте между отправителем и получателем), и пакеты могут быть получены в порядке, отличном от того, в котором вы их отправили.
Ответ №3:
Ну, это не должно быть проблемой в современных ОС, но вы не проверяете возвращаемое значение из malloc() на NULL. На какой строке происходит сбой и с каким сигналом?
Комментарии:
1. он выходит из строя на fopen, как я узнаю, с каким сигналом он выходит из строя? Там написано Malloc — повреждение памяти, если вы это имеете в виду.