Посылает ли метод C свободный буфер? - PullRequest
6 голосов
/ 09 апреля 2011

У меня вопрос по поводу метода отправки C.

int send (int socket, void *buffer, size_t size, int flags);

Мой код:

char *buffer = (char *)malloc(100*sizeof(char));
send(s, buffer, 100*sizeof(char), MSG_NOSIGNAL);

Теперь мне стало интересно, должен ли я освободить буфер самостоятельно или метод send освободит его?

Мой код, где я освобождаю буфер:

char *buffer = (char *)malloc(100*sizeof(char));
send(s, buffer, 100*sizeof(char), MSG_NOSIGNAL);
free(buffer);

Когда я увидел ошибку, мне показалось, что я скоро освободил буфер, а метод send все еще использовал память.

Дайте мне знать.

Ответы [ 5 ]

6 голосов
/ 09 апреля 2011

send не освобождает буфер.Вы должны освободить это.Помимо того факта, что он просто не был спроектирован таким образом (функции сокетов не зависят от функций кучи), send не будет фактически «знать», следует ли освободить память, поскольку это может быть указатель на середину выделенного фрагментапамяти или это может быть указатель на стек данных.

Должно быть "безопасно" немедленно освобождать буфер после вызова send, потому что функция скопирует данные в свои собственные внутренние буферы.Код, который вы показываете, не вызовет проблемы с повреждением (хотя я подозреваю, что задействовано больше кода, так как буфер не инициализирован, как показано).Возможно, что куча будет повреждена ранее в процессе и не вызовет исключение до более позднего момента (например, освобождает после отправки).

Возвращаемое значение send указывает количество успешно отправленных байтов.(хотя не обязательно успешно доставлено).Таким образом, хотя было бы «безопасно» освободить его, вы потеряете неотправленные данные, если они не будут отправлены.Если весь буфер не был отправлен, вам нужно будет снова вызвать send с оставшейся суммой.

1 голос
/ 09 апреля 2011

Вы можете free буфер после возврата вызова send, отмечая следующее:

  • Возможно, весь буфер не был отправлен.
  • Вызов возвращает количество байтов, которые ядро ​​скопировало в свои собственные буферы. Остальное вы должны оставить.

Этот код может помочь вам понять, что происходит, но вы ни в коем случае не должны основывать свои собственные на этом:

char *buf; // sizeof(*buf) must be 1 for pointer arithmetic
ssize_t sent = send(fd, buf, len, 0);
if (sent != -1) { // no error
    // move the unsent bytes to the start of the buffer
    memmove(buf, buf + sent, len - sent);
    // resize the buffer to fit the left over bytes
    buf = realloc(buf, len - sent);
}
0 голосов
/ 09 апреля 2011

Из вашего описания звучит так, как будто вы страдаете от того, что ваш код использует указатель после его освобождения.Существуют хорошие и надежные способы решения проблем такого типа, а также быстрые способы взлома.Вот быстрый взлом:

#define free(p) do { (free)(p); p=(void*)1; } while (0)

Этот макрос, который вы хотели бы включить в заголовочный файл или в первую строку вашего проекта, заменяет ваши бесплатные звонки так, чтобы:

  1. Память все еще free() 'd, нотация (free)(p) заставляет компилятор C вычислять (free) как символ функции, а не расширение макроса.
  2. Указатель установлен на недоступныйзначение, 1. Значение NULL (0) не использовалось, потому что free() не будет жаловаться, если передано NULL.Передача «значения указателя» 1 должна вызвать сообщение об ошибке.

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

0 голосов
/ 09 апреля 2011

В общем, было бы очень необычно, если бы функция API освободила буфер. единственная из известных мне функций, которая освобождает буфер, является «свободной» ...

иногда функции выделяют память, которую вы должны освободить после их использования, например, strdup

есть некоторые функции, где вы не можете освободить буфер непосредственно после их использования. например, в .Net вы не можете удалить указатель данных растрового изображения, если он все еще используется в обертке растрового изображения.

0 голосов
/ 09 апреля 2011

send () не освобождает буфер. Если у вас есть проблемы с двойным освобождением, вы должны посмотреть, где вы их освобождаете, и проверить, как туда добраться.

...