Предоставляет ли 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));
}
Ответы
Ответ 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 не может быть изменено.
- В определении
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;