Подтвердить что ты не робот

Предоставляет ли free() значение errno?

Если buf является malloc() выделенным буфером char, устанавливает free(buf)/reset errno?

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

Скажем, что политика ошибки для кода - вернуть -1 на ошибку.

Является ли это правильным способом записи буфера и проверки ошибок без утечки памяти?

fputs(buf, somefile);
free(buf);
if (errno) return -1;

Или мне нужно рассмотреть возможность бесплатной установки errno, как в...

fputs(buf, somefile);
if (errno){ 
    free(buf);
    return -1;
}
free(buf);

или, ужас ужасов,

do { 
  fputs(buf, somefile);
  int save_errno = errno;
  free(buf);
  errno = save_errno;
  if (errno) return -1;
} while(0);  

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

Все это, казалось бы, зависит от того, устанавливает ли free() errno.

справочная страница linux бесплатно() также является справочной страницей для malloc() и т.д. В ней упоминается malloc() настройка errno, но не free().

Страница руководства библиотеки GNU C для освобождения динамической памяти не упоминает, устанавливает ли free() errno.

Итак, я написал короткую программу для принудительной записи ошибки, чтобы я мог видеть, есть ли free() reset errno, и это не так. Мне интересно, должен ли я полагаться на этот результат и на то, что free() настолько важен, что "конечно, он не устанавливает errno".

# See if free() resets errno on a bad write
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
  char * buf = malloc(256);
  snprintf(buf,256,"%s\n", "Hello, World!");

  FILE *badfile;

  badfile = fopen("/dev/null","r");

  fputs(buf, badfile);
  free(buf);
  printf("%d\n", errno);
  printf("%s\n", strerror(errno));
}
4b9b3361

Ответ 1

POSIX не определяет free для установки errno (хотя POSIX в настоящее время не запрещает его, поэтому реализация может сделайте это - обратитесь к @ArjunShankar answer для получения более подробной информации). Но это не имеет особого отношения к вашей проблеме.

То, как вы проверяете ошибки, неверно. Вы должны проверить возвращаемое значение fputs и проверить, меньше ли оно 0. Если это так, вы можете проверить errno, чтобы узнать, что вызвало сбой, но это необязательно (и должно быть сделано до вызова каких-либо дополнительных функций).

Итак, что-то вроде этого должно сделать трюк:

int result = fputs(buf, somefile);
/* optionally read errno here if result < 0 (before the free call) */
free(buf);
return (result < 0) ? -1 : 0;

Ответ 2

POSIX-совместимый free может установить errno сегодня, но это изменится к лучшему в будущем. Подробности:

Никакая функция в этом томе POSIX.1-2008 не должна устанавливать errno в 0. Установка errno после успешного вызова функции не указывается, если только описание этой функции не указывает, что errno не может быть изменено.

  1. В определении free не указано, что free делает с errno.

Это означает, что совместимая реализация free никогда не будет reset errno до 0. Но она может или не может установить ее на ненулевое значение.

Однако, проблема 8 (текущая работа) спецификации будет требовать free, чтобы конкретно гарантировать, что она не будет установлена ​​errno при передаче действительного ввода.

glibc уже готов к выполнению этого нового требования.

Ответ 3

В описании free в стандарте C ничего не сказано о errno. Поэтому вы не можете полагаться на эту функцию.

В соответствии со стандартом C (7.5 Ошибки <errno.h>)

3... Значение errno может быть установлено на ненулевое значение вызовом функции библиотеки, независимо от наличия или отсутствия ошибки, при условии, что использование errno является не описано в описании функции в этом Международный стандарт.

И использование errno не описано в описании free в стандарте C, как я уже сказал выше.

Ответ 4

Если ссылка не говорит о том, что функция возвращает код ошибки в errno при сбое, это не будет.

Функции, которые устанавливают errno в код ошибки (почти), всегда сигнализируют другим способом, что errno содержит текущий код ошибки - функции выделения памяти возвращают NULL, многие другие функции возвращают нуль или отрицательное число, и т.д.
Такие функции не обязаны изменять errno каким-либо образом, если они преуспевают, и обычно этого не делают.

Обычно вы не можете проверить errno, чтобы определить, что-то пошло не так; он предназначен только для получения дополнительной информации, как только вы знаете, что произошла ошибка.

Единственное исключение из окончательного правила - это семейство strto{l, d, ul}, но первый абзац для них тоже верен. И они также не обязательно устанавливают errno, за исключением случаев, когда они терпят неудачу, поэтому вам нужно сначала очистить его, или он может содержать устаревший код ошибки.

Ответ 5

вы можете использовать RAII для освобождения памяти malloced и проверить возвращаемое значение fputs. Это будет код благодати.

//if malloc successfully
AutoFree af(buf);
if (fputs(buf, somefile)) {
LOG("something err:%s", strerror(errno));
}
return 0;